diff --git a/.i18nrc.json b/.i18nrc.json
index e5ba6762da154..a1c49ae03f359 100644
--- a/.i18nrc.json
+++ b/.i18nrc.json
@@ -17,8 +17,10 @@
"kbn": "src/legacy/core_plugins/kibana",
"kbnDocViews": "src/legacy/core_plugins/kbn_doc_views",
"kbnVislibVisTypes": "src/legacy/core_plugins/kbn_vislib_vis_types",
+ "management": "src/legacy/core_plugins/management",
"kibana_react": "src/legacy/core_plugins/kibana_react",
"kibana-react": "src/plugins/kibana_react",
+ "kibana_utils": "src/plugins/kibana_utils",
"navigation": "src/legacy/core_plugins/navigation",
"newsfeed": "src/plugins/newsfeed",
"regionMap": "src/legacy/core_plugins/region_map",
diff --git a/NOTICE.txt b/NOTICE.txt
index 989bb6f754a09..230e511746022 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -186,32 +186,6 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----
-This product includes code that is based on facebookincubator/idx, which was
-available under a "MIT" license.
-
-MIT License
-
-Copyright (c) 2013-present, Facebook, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---
This product includes code that was extracted from angular@1.3.
Original license:
diff --git a/docs/developer/core/development-functional-tests.asciidoc b/docs/developer/core/development-functional-tests.asciidoc
index 350a3c2a997cf..77a2bfe77b4ab 100644
--- a/docs/developer/core/development-functional-tests.asciidoc
+++ b/docs/developer/core/development-functional-tests.asciidoc
@@ -282,7 +282,7 @@ The `FunctionalTestRunner` comes with three built-in services:
* Source: {blob}src/functional_test_runner/lib/lifecycle.ts[src/functional_test_runner/lib/lifecycle.ts]
* Designed primary for use in services
* Exposes lifecycle events for basic coordination. Handlers can return a promise and resolve/fail asynchronously
-* Phases include: `beforeLoadTests`, `beforeTests`, `beforeEachTest`, `cleanup`, `phaseStart`, `phaseEnd`
+* Phases include: `beforeLoadTests`, `beforeTests`, `beforeEachTest`, `cleanup`
[float]
===== Kibana Services
diff --git a/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md b/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md
index 960d610b589b8..e01a5e9da50d5 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md
@@ -17,6 +17,7 @@ core: {
i18n: I18nStart;
notifications: NotificationsStart;
overlays: OverlayStart;
+ savedObjects: SavedObjectsStart;
uiSettings: IUiSettingsClient;
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
diff --git a/docs/development/core/public/kibana-plugin-public.appmountcontext.md b/docs/development/core/public/kibana-plugin-public.appmountcontext.md
index e12121e0e3ebb..68a1c27b11836 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountcontext.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountcontext.md
@@ -16,5 +16,5 @@ export interface AppMountContext
| Property | Type | Description |
| --- | --- | --- |
-| [core](./kibana-plugin-public.appmountcontext.core.md) | {
application: Pick<ApplicationStart, 'capabilities' | 'navigateToApp'>;
chrome: ChromeStart;
docLinks: DocLinksStart;
http: HttpStart;
i18n: I18nStart;
notifications: NotificationsStart;
overlays: OverlayStart;
uiSettings: IUiSettingsClient;
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
};
}
| Core service APIs available to mounted applications. |
+| [core](./kibana-plugin-public.appmountcontext.core.md) | {
application: Pick<ApplicationStart, 'capabilities' | 'navigateToApp'>;
chrome: ChromeStart;
docLinks: DocLinksStart;
http: HttpStart;
i18n: I18nStart;
notifications: NotificationsStart;
overlays: OverlayStart;
savedObjects: SavedObjectsStart;
uiSettings: IUiSettingsClient;
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
};
}
| Core service APIs available to mounted applications. |
diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.md
index dba0ad8c8560c..25eebf1c06d01 100644
--- a/docs/development/core/server/kibana-plugin-server.httpservicesetup.md
+++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.md
@@ -23,6 +23,7 @@ export interface HttpServiceSetup
| [registerAuth](./kibana-plugin-server.httpservicesetup.registerauth.md) | (handler: AuthenticationHandler) => void
| To define custom authentication and/or authorization mechanism for incoming requests. |
| [registerOnPostAuth](./kibana-plugin-server.httpservicesetup.registeronpostauth.md) | (handler: OnPostAuthHandler) => void
| To define custom logic to perform for incoming requests. |
| [registerOnPreAuth](./kibana-plugin-server.httpservicesetup.registeronpreauth.md) | (handler: OnPreAuthHandler) => void
| To define custom logic to perform for incoming requests. |
+| [registerOnPreResponse](./kibana-plugin-server.httpservicesetup.registeronpreresponse.md) | (handler: OnPreResponseHandler) => void
| To define custom logic to perform for the server response. |
| [registerRouteHandlerContext](./kibana-plugin-server.httpservicesetup.registerroutehandlercontext.md) | <T extends keyof RequestHandlerContext>(contextName: T, provider: RequestHandlerContextProvider<T>) => RequestHandlerContextContainer
| Register a context provider for a route handler. |
## Example
diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpreresponse.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpreresponse.md
new file mode 100644
index 0000000000000..9f0eaae8830e1
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpreresponse.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [registerOnPreResponse](./kibana-plugin-server.httpservicesetup.registeronpreresponse.md)
+
+## HttpServiceSetup.registerOnPreResponse property
+
+To define custom logic to perform for the server response.
+
+Signature:
+
+```typescript
+registerOnPreResponse: (handler: OnPreResponseHandler) => void;
+```
+
+## Remarks
+
+Doesn't provide the whole response object. Supports extending response with custom headers. See [OnPreResponseHandler](./kibana-plugin-server.onpreresponsehandler.md).
+
diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md
index 9144742c9bb73..fceabd1237665 100644
--- a/docs/development/core/server/kibana-plugin-server.md
+++ b/docs/development/core/server/kibana-plugin-server.md
@@ -77,6 +77,9 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [LogMeta](./kibana-plugin-server.logmeta.md) | Contextual metadata |
| [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md) | A tool set defining an outcome of OnPostAuth interceptor for incoming request. |
| [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. |
+| [OnPreResponseExtensions](./kibana-plugin-server.onpreresponseextensions.md) | Additional data to extend a response. |
+| [OnPreResponseInfo](./kibana-plugin-server.onpreresponseinfo.md) | Response status code. |
+| [OnPreResponseToolkit](./kibana-plugin-server.onpreresponsetoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. |
| [PackageInfo](./kibana-plugin-server.packageinfo.md) | |
| [Plugin](./kibana-plugin-server.plugin.md) | The interface that should be returned by a PluginInitializer
. |
| [PluginConfigDescriptor](./kibana-plugin-server.pluginconfigdescriptor.md) | Describes a plugin configuration schema and capabilities. |
@@ -173,6 +176,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [MutatingOperationRefreshSetting](./kibana-plugin-server.mutatingoperationrefreshsetting.md) | Elasticsearch Refresh setting for mutating operation |
| [OnPostAuthHandler](./kibana-plugin-server.onpostauthhandler.md) | See [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md). |
| [OnPreAuthHandler](./kibana-plugin-server.onpreauthhandler.md) | See [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md). |
+| [OnPreResponseHandler](./kibana-plugin-server.onpreresponsehandler.md) | See [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md). |
| [PluginConfigSchema](./kibana-plugin-server.pluginconfigschema.md) | Dedicated type for plugin configuration schema. |
| [PluginInitializer](./kibana-plugin-server.plugininitializer.md) | The plugin
export at the root of a plugin's server
directory should conform to this interface. |
| [PluginName](./kibana-plugin-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. |
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponseextensions.headers.md b/docs/development/core/server/kibana-plugin-server.onpreresponseextensions.headers.md
new file mode 100644
index 0000000000000..8736020daf063
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponseextensions.headers.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseExtensions](./kibana-plugin-server.onpreresponseextensions.md) > [headers](./kibana-plugin-server.onpreresponseextensions.headers.md)
+
+## OnPreResponseExtensions.headers property
+
+additional headers to attach to the response
+
+Signature:
+
+```typescript
+headers?: ResponseHeaders;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponseextensions.md b/docs/development/core/server/kibana-plugin-server.onpreresponseextensions.md
new file mode 100644
index 0000000000000..e5aa624c39909
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponseextensions.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseExtensions](./kibana-plugin-server.onpreresponseextensions.md)
+
+## OnPreResponseExtensions interface
+
+Additional data to extend a response.
+
+Signature:
+
+```typescript
+export interface OnPreResponseExtensions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [headers](./kibana-plugin-server.onpreresponseextensions.headers.md) | ResponseHeaders
| additional headers to attach to the response |
+
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponsehandler.md b/docs/development/core/server/kibana-plugin-server.onpreresponsehandler.md
new file mode 100644
index 0000000000000..082de0a9b4aeb
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponsehandler.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseHandler](./kibana-plugin-server.onpreresponsehandler.md)
+
+## OnPreResponseHandler type
+
+See [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md).
+
+Signature:
+
+```typescript
+export declare type OnPreResponseHandler = (request: KibanaRequest, preResponse: OnPreResponseInfo, toolkit: OnPreResponseToolkit) => OnPreResponseResult | Promise;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponseinfo.md b/docs/development/core/server/kibana-plugin-server.onpreresponseinfo.md
new file mode 100644
index 0000000000000..736b4298037cf
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponseinfo.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseInfo](./kibana-plugin-server.onpreresponseinfo.md)
+
+## OnPreResponseInfo interface
+
+Response status code.
+
+Signature:
+
+```typescript
+export interface OnPreResponseInfo
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [statusCode](./kibana-plugin-server.onpreresponseinfo.statuscode.md) | number
| |
+
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponseinfo.statuscode.md b/docs/development/core/server/kibana-plugin-server.onpreresponseinfo.statuscode.md
new file mode 100644
index 0000000000000..4fd4529dc400f
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponseinfo.statuscode.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseInfo](./kibana-plugin-server.onpreresponseinfo.md) > [statusCode](./kibana-plugin-server.onpreresponseinfo.statuscode.md)
+
+## OnPreResponseInfo.statusCode property
+
+Signature:
+
+```typescript
+statusCode: number;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponsetoolkit.md b/docs/development/core/server/kibana-plugin-server.onpreresponsetoolkit.md
new file mode 100644
index 0000000000000..5525f5bf60284
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponsetoolkit.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseToolkit](./kibana-plugin-server.onpreresponsetoolkit.md)
+
+## OnPreResponseToolkit interface
+
+A tool set defining an outcome of OnPreAuth interceptor for incoming request.
+
+Signature:
+
+```typescript
+export interface OnPreResponseToolkit
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [next](./kibana-plugin-server.onpreresponsetoolkit.next.md) | (responseExtensions?: OnPreResponseExtensions) => OnPreResponseResult
| To pass request to the next handler |
+
diff --git a/docs/development/core/server/kibana-plugin-server.onpreresponsetoolkit.next.md b/docs/development/core/server/kibana-plugin-server.onpreresponsetoolkit.next.md
new file mode 100644
index 0000000000000..bfb5827b16b2f
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.onpreresponsetoolkit.next.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [OnPreResponseToolkit](./kibana-plugin-server.onpreresponsetoolkit.md) > [next](./kibana-plugin-server.onpreresponsetoolkit.next.md)
+
+## OnPreResponseToolkit.next property
+
+To pass request to the next handler
+
+Signature:
+
+```typescript
+next: (responseExtensions?: OnPreResponseExtensions) => OnPreResponseResult;
+```
diff --git a/docs/management/field-formatters/url-formatter.asciidoc b/docs/management/field-formatters/url-formatter.asciidoc
index 2cbade4431202..41d4f75603dc6 100644
--- a/docs/management/field-formatters/url-formatter.asciidoc
+++ b/docs/management/field-formatters/url-formatter.asciidoc
@@ -4,6 +4,8 @@ The `Url` field formatter can take on the following types:
* The *Image* type can be used to specify an image directory where a specified image is located.
* The *Audio* type can be used to specify an audio directory where a specified audio file is located.
+For an *Image* type you can specify width and height attributes. These will be used to set the max width / max height of the image, while keeping the aspect ratio. Image will not be upscaled if it's smaller than the provided size parameters.
+
You can customize either type of URL field formats with templates. A _URL template_ enables you to add specific values
to a partial URL. Use the string `{{value}}` to add the contents of the field to a fixed URL.
diff --git a/docs/maps/connect-to-ems.asciidoc b/docs/maps/connect-to-ems.asciidoc
index c983fa2cfe4ba..37fbc6d78c8e4 100644
--- a/docs/maps/connect-to-ems.asciidoc
+++ b/docs/maps/connect-to-ems.asciidoc
@@ -13,11 +13,20 @@ EMS requests are made to the following domains:
* vector.maps.elastic.co
**Elastic Maps** makes requests directly from the browser to EMS.
-To proxy EMS requests through the Kibana server, set `map.proxyElasticMapsServiceInMaps` to `true` in your <> file.
+
+[float]
+=== Connect to Elastic Maps Service from an internal network
+
+To connect to EMS when your Kibana server and browser are in an internal network:
+
+. Set `map.proxyElasticMapsServiceInMaps` to `true` in your <> file to proxy EMS requests through the Kibana server.
+. Update your firewall rules to whitelist connections from your Kibana server to the EMS domains listed above.
+
+NOTE: Coordinate map and region map visualizations do not support `map.proxyElasticMapsServiceInMaps` and will not proxy EMS requests through the Kibana server.
[float]
-=== Disabling Elastic Maps Service
+=== Disable Elastic Maps Service
You might experience EMS connection issues if your Kibana server or browser are on a private network or
behind a firewall. If this happens, you can disable the EMS connection to avoid unnecessary EMS requests.
diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc
index 5605ed5c56688..39c87d97af4ba 100644
--- a/docs/setup/settings.asciidoc
+++ b/docs/setup/settings.asciidoc
@@ -147,6 +147,36 @@ will default to `true`.
`logging.quiet:`:: *Default: false* Set the value of this setting to `true` to
suppress all logging output other than error messages.
+`logging.rotate:`:: [experimental] Specifies the options for the logging rotate feature.
+When not defined, all the sub options defaults would be applied.
+The following example shows a valid logging rotate configuration:
++
+--
+ logging.rotate:
+ enabled: true
+ everyBytes: 10485760
+ keepFiles: 10
+--
+
+`logging.rotate.enabled:`:: [experimental] *Default: false* Set the value of this setting to `true` to
+enable log rotation. If you do not have a `logging.dest` set that is different from `stdout`
+that feature would not take any effect.
+
+`logging.rotate.everyBytes:`:: [experimental] *Default: 10485760* The maximum size of a log file (that is `not an exact` limit). After the
+limit is reached, a new log file is generated. The default size limit is 10485760 (10 MB) and
+this option should be at least greater than 1024.
+
+`logging.rotate.keepFiles:`:: [experimental] *Default: 7* The number of most recent rotated log files to keep
+on disk. Older files are deleted during log rotation. The default value is 7. The `logging.rotate.keepFiles`
+option has to be in the range of 2 to 1024 files.
+
+`logging.rotate.pollingInterval:`:: [experimental] *Default: 10000* The number of milliseconds for the polling strategy in case
+the `logging.rotate.usePolling` is enabled. That option has to be in the range of 5000 to 3600000 milliseconds.
+
+`logging.rotate.usePolling:`:: [experimental] *Default: false* By default we try to understand the best way to monitoring
+the log file. However, there is some systems where it could not be always accurate. In those cases, if needed,
+the `polling` method could be used enabling that option.
+
`logging.silent:`:: *Default: false* Set the value of this setting to `true` to
suppress all logging output.
diff --git a/docs/visualize/most-frequent.asciidoc b/docs/visualize/most-frequent.asciidoc
index 7452f1c4c3d7e..e9085d18185ec 100644
--- a/docs/visualize/most-frequent.asciidoc
+++ b/docs/visualize/most-frequent.asciidoc
@@ -7,20 +7,19 @@ levels of {es} {ref}/search-aggregations-bucket.html[bucket] aggregations.
The most frequently used visualizations include:
-* Line, Area and Bar charts
+* Line, area, and bar charts
* Pie charts
-* Data table
-* Metric visualization
-* Goal and Gauge visualization
+* Data tables
+* Metric, goals, and gauges
* Heat maps
-* Tag cloud
+* Tag clouds
[float]
=== Configure your visualization
-You configure visualizations using the default editor, which is broken into *Metrics* and *Buckets*, and includes a default count
+You configure visualizations using the default editor, which is broken into metrics and buckets, and includes a default count
metric. Each visualization supports different configurations for what the metrics and buckets
-represent. For example, a Bar chart allows you to add an X-axis:
+represent. For example, a bar chart allows you to add an X-axis:
[role="screenshot"]
image::images/add-bucket.png["",height=478]
diff --git a/package.json b/package.json
index c3d19367e8b92..8ccb138a3aced 100644
--- a/package.json
+++ b/package.json
@@ -88,7 +88,8 @@
"**/image-diff/gm/debug": "^2.6.9",
"**/react-dom": "^16.12.0",
"**/react-test-renderer": "^16.12.0",
- "**/deepmerge": "^4.2.2"
+ "**/deepmerge": "^4.2.2",
+ "**/serialize-javascript": "^2.1.1"
},
"workspaces": {
"packages": [
@@ -112,7 +113,7 @@
"@elastic/charts": "^14.0.0",
"@elastic/datemath": "5.0.2",
"@elastic/ems-client": "1.0.5",
- "@elastic/eui": "16.1.0",
+ "@elastic/eui": "17.0.0",
"@elastic/filesaver": "1.1.2",
"@elastic/good": "8.1.1-kibana2",
"@elastic/numeral": "2.3.3",
@@ -149,6 +150,7 @@
"cache-loader": "^4.1.0",
"chalk": "^2.4.2",
"check-disk-space": "^2.1.0",
+ "chokidar": "3.2.1",
"color": "1.0.3",
"commander": "3.0.0",
"compare-versions": "3.5.1",
@@ -165,6 +167,7 @@
"encode-uri-query": "1.0.1",
"execa": "^3.2.0",
"expiry-js": "0.1.7",
+ "fast-deep-equal": "^3.1.1",
"file-loader": "4.2.0",
"font-awesome": "4.7.0",
"getos": "^3.1.0",
@@ -228,6 +231,7 @@
"react-resize-detector": "^4.2.0",
"react-router-dom": "^4.3.1",
"react-sizeme": "^2.3.6",
+ "react-use": "^13.10.2",
"reactcss": "1.2.3",
"redux": "4.0.0",
"redux-actions": "2.2.1",
@@ -357,8 +361,8 @@
"@types/uuid": "^3.4.4",
"@types/vinyl-fs": "^2.4.11",
"@types/zen-observable": "^0.8.0",
- "@typescript-eslint/eslint-plugin": "^2.9.0",
- "@typescript-eslint/parser": "^2.9.0",
+ "@typescript-eslint/eslint-plugin": "^2.10.0",
+ "@typescript-eslint/parser": "^2.10.0",
"angular-mocks": "^1.7.8",
"archiver": "^3.1.1",
"axe-core": "^3.3.2",
@@ -370,7 +374,6 @@
"chai": "3.5.0",
"chance": "1.0.18",
"cheerio": "0.22.0",
- "chokidar": "3.2.1",
"chromedriver": "78.0.1",
"classnames": "2.2.6",
"dedent": "^0.7.0",
diff --git a/packages/eslint-config-kibana/.eslintrc.js b/packages/eslint-config-kibana/.eslintrc.js
index 98fa62021b5bb..a7bce739ba8e3 100644
--- a/packages/eslint-config-kibana/.eslintrc.js
+++ b/packages/eslint-config-kibana/.eslintrc.js
@@ -28,6 +28,11 @@ module.exports = {
to: false,
disallowedMessage: `Don't use 'mkdirp', use the new { recursive: true } option of Fs.mkdir instead`
},
+ {
+ from: '@kbn/elastic-idx',
+ to: false,
+ disallowedMessage: `Don't use idx(), use optional chaining syntax instead https://ela.st/optchain`
+ },
{
from: 'x-pack',
toRelative: 'x-pack',
diff --git a/packages/eslint-config-kibana/package.json b/packages/eslint-config-kibana/package.json
index ee65a1cf79148..7917297883b03 100644
--- a/packages/eslint-config-kibana/package.json
+++ b/packages/eslint-config-kibana/package.json
@@ -15,8 +15,8 @@
},
"homepage": "https://github.com/elastic/eslint-config-kibana#readme",
"peerDependencies": {
- "@typescript-eslint/eslint-plugin": "^2.9.0",
- "@typescript-eslint/parser": "^2.9.0",
+ "@typescript-eslint/eslint-plugin": "^2.10.0",
+ "@typescript-eslint/parser": "^2.10.0",
"babel-eslint": "^10.0.3",
"eslint": "^6.5.1",
"eslint-plugin-babel": "^5.3.0",
diff --git a/packages/kbn-babel-preset/common_preset.js b/packages/kbn-babel-preset/common_preset.js
index d1b7bc20dd9f9..0de9318ea0c27 100644
--- a/packages/kbn-babel-preset/common_preset.js
+++ b/packages/kbn-babel-preset/common_preset.js
@@ -35,13 +35,6 @@ const plugins = [
// Need this since we are using TypeScript 3.7+
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
];
-const isTestEnv = process.env.BABEL_ENV === 'test' || process.env.NODE_ENV === 'test';
-
-// Only load the idx plugin in non-test environments, since it conflicts with
-// Jest's coverage mapping.
-if (!isTestEnv) {
- plugins.push(require.resolve('@kbn/elastic-idx/babel'));
-}
module.exports = {
presets: [require.resolve('@babel/preset-typescript'), require.resolve('@babel/preset-react')],
diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json
index 1913301e21a76..e554859928c0b 100644
--- a/packages/kbn-babel-preset/package.json
+++ b/packages/kbn-babel-preset/package.json
@@ -12,7 +12,6 @@
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.3.3",
- "@kbn/elastic-idx": "1.0.0",
"babel-plugin-add-module-exports": "^1.0.2",
"babel-plugin-filter-imports": "^3.0.0",
"babel-plugin-transform-define": "^1.3.1",
diff --git a/packages/kbn-elastic-idx/.npmignore b/packages/kbn-elastic-idx/.npmignore
deleted file mode 100644
index ece13b72c93ea..0000000000000
--- a/packages/kbn-elastic-idx/.npmignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/tsconfig.json
-/src
-/babel/index.test.js
diff --git a/packages/kbn-elastic-idx/README.md b/packages/kbn-elastic-idx/README.md
deleted file mode 100644
index 81cd5d0f86e9b..0000000000000
--- a/packages/kbn-elastic-idx/README.md
+++ /dev/null
@@ -1,76 +0,0 @@
-Kibana elastic-idx Library
-==========================
-
-The `@kbn/elastic-idx` package provides the `idx` function used for optional
-chaining. Currently, the optional chaining draft is in stage 1, making it too
-uncertain to add syntax support within Kibana. Other optional chaining
-libraries require the Proxy object to be polyfilled for browser support,
-however, this polyfill is not fully supported across all browsers that Kibana
-requires. The facebookincubator `idx` project
-(https://github.com/facebookincubator/idx) provides an answer to this with a
-specific implementation that is understood by TypeScript so that type
-information does not get lost (unlike lodash get) The `@kbn/elastic-idx`
-library makes use the `idx` idiom but differs in the way null values within the
-property chain are handled.
-
-Similar to the facebookincubator `idx` project, `@kbn/elastic-idx` also
-provides the Babel plugin to transform `idx()` function calls into the expanded
-form. This Babel plugin was based off the facebookincubator `idx` Babel
-plugin, since the invocation syntax is almost identical, but the transformed
-code differs to match how the `@kbn/elastic-idx` library treats null values.
-
-App Usage
-----------
-Within Kibana, `@kbn/elastic-idx` can be imported and used in any JavaScript or
-TypeScript project:
-
-```
-import { idx } from '@kbn/elastic-idx';
-
-const obj0 = { a: { b: { c: { d: 'iamdefined' } } } };
-const obj1 = { a: { b: null } };
-
-idx(obj0, _ => _.a.b.c.d); // returns 'iamdefined'
-idx(obj1, _ => _.a.b.c.e); // returns undefined
-idx(obj1, _ => _.a.b); // returns null
-```
-
-Build Optimization
--------------------
-Similar to the facebookincubator `idx` project, it is NOT RECOMMENDED to use
-idx in shipped app code. The implementation details which make
-`@kbn/elastic-idx` possible comes at a non-negligible performance cost. This
-usually isn't noticable during development, but for production builds, it is
-recommended to transform idx calls into native, expanded form JS. Use the
-plugin `@kbn/elastic-idx/babel` within your Babel configuration:
-
-```
-{ "plugins": [ "@kbn/elastic-idx/babel" ] }
-```
-
-The resulting Babel transforms the following:
-
-```
-import { idx } from '@kbn/elastic-idx';
-const obj = { a: { b: { c: { d: 'iamdefined' } } } };
-idx(obj, _ => _.a.b.c.d);
-```
-
-into this:
-
-```
-obj != null &&
-obj.a != null &&
-obj.a.b != null &&
-obj.a.b.c != null ?
-obj.a.b.c.d : undefined
-```
-
-Note that this also removes the import statement from the source code, since it
-no longer needs to be bundled.
-
-Testing
---------
-
-Tests can be run with `npm test`. This includes "functional" tests that
-transform and evaluate idx calls.
diff --git a/packages/kbn-elastic-idx/babel/index.js b/packages/kbn-elastic-idx/babel/index.js
deleted file mode 100644
index 89171e3565530..0000000000000
--- a/packages/kbn-elastic-idx/babel/index.js
+++ /dev/null
@@ -1,304 +0,0 @@
-/* eslint-disable @kbn/eslint/require-license-header */
-
-/* @notice
- * This product includes code that is based on facebookincubator/idx, which was
- * available under a "MIT" license.
- *
- * MIT License
- *
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* eslint strict: 0, new-cap: 0 */
-
-'use strict';
-module.exports = context => {
- const t = context.types;
-
- const idxRe = /\bidx\b/;
-
- function checkIdxArguments(file, node) {
- const args = node.arguments;
- if (args.length !== 2) {
- throw file.buildCodeFrameError(node, 'The `idx` function takes exactly two arguments.');
- }
- const arrowFunction = args[1];
- if (!t.isArrowFunctionExpression(arrowFunction)) {
- throw file.buildCodeFrameError(
- arrowFunction,
- 'The second argument supplied to `idx` must be an arrow function.'
- );
- }
- if (!t.isExpression(arrowFunction.body)) {
- throw file.buildCodeFrameError(
- arrowFunction.body,
- 'The body of the arrow function supplied to `idx` must be a single ' +
- 'expression (without curly braces).'
- );
- }
- if (arrowFunction.params.length !== 1) {
- throw file.buildCodeFrameError(
- arrowFunction.params[2] || arrowFunction,
- 'The arrow function supplied to `idx` must take exactly one parameter.'
- );
- }
- const input = arrowFunction.params[0];
- if (!t.isIdentifier(input)) {
- throw file.buildCodeFrameError(
- arrowFunction.params[0],
- 'The parameter supplied to `idx` must be an identifier.'
- );
- }
- }
-
- function checkIdxBindingNode(file, node) {
- if (t.isImportDeclaration(node)) {
- // E.g. `import '...'`
- if (node.specifiers.length === 0) {
- throw file.buildCodeFrameError(node, 'The idx import must have a value.');
- }
- // E.g. `import A, {B} from '...'`
- // `import A, * as B from '...'`
- // `import {A, B} from '...'`
- if (node.specifiers.length > 1) {
- throw file.buildCodeFrameError(
- node.specifiers[1],
- 'The idx import must be a single specifier.'
- );
- }
- // `importKind` is not a property unless flow syntax is enabled.
- // On specifiers, `importKind` is not "value" when it's not a type, it's
- // `null`.
- // E.g. `import type {...} from '...'`
- // `import typeof {...} from '...'`
- // `import {type ...} from '...'`.
- // `import {typeof ...} from '...'`
- if (
- node.importKind === 'type' ||
- node.importKind === 'typeof' ||
- node.specifiers[0].importKind === 'type' ||
- node.specifiers[0].importKind === 'typeof'
- ) {
- throw file.buildCodeFrameError(node, 'The idx import must be a value import.');
- }
- } else if (t.isVariableDeclarator(node)) {
- // E.g. var {idx} or var [idx]
- if (!t.isIdentifier(node.id)) {
- throw file.buildCodeFrameError(
- node.specifiers[0],
- 'The idx declaration must be an identifier.'
- );
- }
- }
- }
-
- class UnsupportedNodeTypeError extends Error {
- constructor(node, ...params) {
- super(`Node type is not supported: ${node.type}`, ...params);
- if (Error.captureStackTrace) {
- Error.captureStackTrace(this, UnsupportedNodeTypeError);
- }
-
- this.name = 'UnsupportedNodeTypeError';
- }
- }
-
- function getDeepProperties(node, properties = [], computedProperties = new Set()) {
- if (t.isMemberExpression(node)) {
- if (node.computed) {
- computedProperties.add(node.property);
- }
- return getDeepProperties(node.object, [node.property, ...properties], computedProperties);
- } else if (t.isIdentifier(node)) {
- return [[node, ...properties], computedProperties];
- }
-
- throw new UnsupportedNodeTypeError(node);
- }
-
- function buildMemberChain(properties, computedProperties) {
- if (properties.length > 1) {
- const lead = properties.slice(0, properties.length - 1);
- const last = properties[properties.length - 1];
- return t.MemberExpression(
- buildMemberChain(lead, computedProperties),
- last,
- computedProperties.has(last)
- );
- } else if (properties.length === 1) {
- return properties[0];
- }
- return t.identifier('undefined');
- }
-
- function buildExpandedMemberNullChecks(
- leadingProperties = [],
- trailingProperties = [],
- computedProperties
- ) {
- const propertyChainNullCheck = t.BinaryExpression(
- '!=',
- buildMemberChain(leadingProperties, computedProperties),
- t.NullLiteral()
- );
-
- if (trailingProperties.length <= 1) {
- return propertyChainNullCheck;
- }
-
- const [headTrailingProperty, ...tailProperties] = trailingProperties;
-
- return t.LogicalExpression(
- '&&',
- propertyChainNullCheck,
- buildExpandedMemberNullChecks(
- [...leadingProperties, headTrailingProperty],
- tailProperties,
- computedProperties
- )
- );
- }
-
- function buildExpandedMemberAccess(node, state) {
- let baseNode;
- let properties;
- let computedProperties;
-
- try {
- [[baseNode, ...properties], computedProperties] = getDeepProperties(node);
- } catch (error) {
- if (error instanceof UnsupportedNodeTypeError) {
- throw state.file.buildCodeFrameError(
- node,
- 'idx callbacks may only access properties on the callback parameter.'
- );
- }
-
- throw error;
- }
-
- if (baseNode.name !== state.base.name) {
- throw state.file.buildCodeFrameError(
- node,
- 'The parameter of the arrow function supplied to `idx` must match ' +
- 'the base of the body expression.'
- );
- }
- return t.ConditionalExpression(
- buildExpandedMemberNullChecks([state.input], properties, computedProperties),
- buildMemberChain([state.input, ...properties], computedProperties),
- t.identifier('undefined')
- );
- }
-
- function visitIdxCallExpression(path, state) {
- const node = path.node;
- checkIdxArguments(state.file, node);
- const replacement = buildExpandedMemberAccess(node.arguments[1].body, {
- file: state.file,
- input: node.arguments[0],
- base: node.arguments[1].params[0],
- });
- path.replaceWith(replacement);
- }
-
- function isIdxImportOrRequire(node, name) {
- if (t.isImportDeclaration(node)) {
- if (name instanceof RegExp) {
- return name.test(node.source.value);
- } else {
- return t.isStringLiteral(node.source, { value: name });
- }
- } else if (t.isVariableDeclarator(node)) {
- return (
- t.isCallExpression(node.init) &&
- t.isIdentifier(node.init.callee, { name: 'require' }) &&
- (name instanceof RegExp
- ? name.test(node.init.arguments[0].value)
- : t.isLiteral(node.init.arguments[0], { value: name }))
- );
- } else {
- return false;
- }
- }
-
- const declareVisitor = {
- 'ImportDeclaration|VariableDeclarator'(path, state) {
- if (!isIdxImportOrRequire(path.node, state.importName)) {
- return;
- }
-
- checkIdxBindingNode(state.file, path.node);
-
- const bindingName = t.isImportDeclaration(path.node)
- ? path.node.specifiers[0].local.name
- : path.node.id.name;
- const idxBinding = path.scope.getOwnBinding(bindingName);
-
- idxBinding.constantViolations.forEach(refPath => {
- throw state.file.buildCodeFrameError(refPath.node, '`idx` cannot be redefined.');
- });
-
- let didTransform = false;
- let didSkip = false;
-
- // Traverse the references backwards to process inner calls before
- // outer calls.
- idxBinding.referencePaths
- .slice()
- .reverse()
- .forEach(refPath => {
- if (refPath.node === idxBinding.node) {
- // Do nothing...
- } else if (refPath.parentPath.isMemberExpression()) {
- visitIdxCallExpression(refPath.parentPath.parentPath, state);
- didTransform = true;
- } else if (refPath.parentPath.isCallExpression()) {
- visitIdxCallExpression(refPath.parentPath, state);
- didTransform = true;
- } else {
- // Should this throw?
- didSkip = true;
- }
- });
- if (didTransform && !didSkip) {
- path.remove();
- }
- },
- };
-
- return {
- visitor: {
- Program(path, state) {
- const importName = state.opts.importName || '@kbn/elastic-idx';
- // If there can't reasonably be an idx call, exit fast.
- if (importName !== '@kbn/elastic-idx' || idxRe.test(state.file.code)) {
- // We're very strict about the shape of idx. Some transforms, like
- // "babel-plugin-transform-async-to-generator", will convert arrow
- // functions inside async functions into regular functions. So we do
- // our transformation before any one else interferes.
- const newState = { file: state.file, importName };
- path.traverse(declareVisitor, newState);
- }
- },
- },
- };
-};
diff --git a/packages/kbn-elastic-idx/babel/index.test.js b/packages/kbn-elastic-idx/babel/index.test.js
deleted file mode 100644
index c4aee5266d6fa..0000000000000
--- a/packages/kbn-elastic-idx/babel/index.test.js
+++ /dev/null
@@ -1,694 +0,0 @@
-/* eslint-disable @kbn/eslint/require-license-header */
-
-/* @notice
- * This product includes code that is based on facebookincubator/idx, which was
- * available under a "MIT" license.
- *
- * MIT License
- *
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-'use strict'; // eslint-disable-line strict
-
-jest.autoMockOff();
-
-const { transformSync: babelTransform } = require('@babel/core');
-const babelPluginIdx = require('./index');
-const transformAsyncToGenerator = require('@babel/plugin-transform-async-to-generator');
-const vm = require('vm');
-
-function transform(source, plugins, options) {
- return babelTransform(source, {
- plugins: plugins || [[babelPluginIdx, options]],
- babelrc: false,
- highlightCode: false,
- }).code;
-}
-
-const asyncToGeneratorHelperCode = `
-function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
- try {
- var info = gen[key](arg);
- var value = info.value;
- } catch (error) {
- reject(error);
- return;
- }
- if (info.done) {
- resolve(value);
- } else {
- Promise.resolve(value).then(_next, _throw);
- }
-}
-
-function _asyncToGenerator(fn) {
- return function() {
- var self = this,
- args = arguments;
- return new Promise(function(resolve, reject) {
- var gen = fn.apply(self, args);
-
- function _next(value) {
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
- }
-
- function _throw(err) {
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
- }
- _next(undefined);
- });
- };
-}
-`;
-
-function stringByTrimmingSpaces(string) {
- return string.replace(/\s+/g, '');
-}
-
-expect.extend({
- toTransformInto: (input, expected) => {
- const plugins = typeof input === 'string' ? null : input.plugins;
- const options = typeof input === 'string' ? undefined : input.options;
- const code = typeof input === 'string' ? input : input.code;
- const actual = transform(code, plugins, options);
- const pass = stringByTrimmingSpaces(actual) === stringByTrimmingSpaces(expected);
- return {
- pass,
- message: () =>
- 'Expected input to transform into:\n' + expected + '\n' + 'Instead, got:\n' + actual,
- };
- },
- toThrowTransformError: (input, expected) => {
- try {
- const plugins = typeof input === 'string' ? null : input.plugins;
- const options = typeof input === 'string' ? undefined : input.options;
- const code = typeof input === 'string' ? input : input.code;
- transform(code, plugins, options);
- } catch (error) {
- const actual = /^.+:\s*(.*)/.exec(error.message)[1]; // Strip "undefined: " and code snippet
- return {
- pass: actual === expected,
- message: () =>
- 'Expected transform to throw "' + expected + '", but instead ' + 'got "' + actual + '".',
- };
- }
- return {
- pass: false,
- message: () => 'Expected transform to throw "' + expected + '".',
- };
- },
- toReturn: (input, expected) => {
- const code = transform(input, undefined);
- const actual = vm.runInNewContext(code);
- return {
- pass: actual === expected,
- message: () => 'Expected "' + expected + '" but got "' + actual + '".',
- };
- },
-});
-
-describe('kbn-babel-plugin-apm-idx', () => {
- it('transforms member expressions', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _.b.c.d.e);
- `).toTransformInto(`
- base != null && base.b != null && base.b.c != null && base.b.c.d != null
- ? base.b.c.d.e
- : undefined;
- `);
- });
-
- it('throws on call expressions', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _.b.c(...foo)().d(bar, null, [...baz]));
- `).toThrowTransformError('idx callbacks may only access properties on the callback parameter.');
- });
-
- it('transforms bracket notation', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _["b"][0][c + d]);
- `).toTransformInto(`
- base != null && base["b"] != null && base["b"][0] != null ? base["b"][0][c + d] : undefined;
- `);
- });
-
- it('throws on bracket notation call expressions', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _["b"](...foo)()[0][c + d](bar, null, [...baz]));
- `).toThrowTransformError('idx callbacks may only access properties on the callback parameter.');
- });
-
- it('transforms combination of both member access notations', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _.a["b"].c[d[e[f]]].g);
- `).toTransformInto(`
- base != null && base.a != null && base.a["b"] != null && base.a["b"].c != null && base.a["b"].c[d[e[f]]] != null
- ? base.a["b"].c[d[e[f]]].g
- : undefined;
- `);
- });
-
- it('transforms if the base is an expression', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(this.props.base[5], _ => _.property);
- `).toTransformInto(`
- this.props.base[5] != null ? this.props.base[5].property : undefined;
- `);
- });
-
- it('throws if the arrow function has more than one param', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, (a, b) => _.property);
- `).toThrowTransformError(
- 'The arrow function supplied to `idx` must take exactly one parameter.'
- );
- });
-
- it('throws if the arrow function has an invalid base', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, a => b.property)
- `).toThrowTransformError(
- 'The parameter of the arrow function supplied to `idx` must match the ' +
- 'base of the body expression.'
- );
- });
-
- it('throws if the arrow function expression has non-properties/methods', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => (_.a++).b.c);
- `).toThrowTransformError('idx callbacks may only access properties on the callback parameter.');
- });
-
- it('throws if the body of the arrow function is not an expression', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => {})
- `).toThrowTransformError(
- 'The body of the arrow function supplied to `idx` must be a single ' +
- 'expression (without curly braces).'
- );
- });
-
- it('ignores non-function call idx', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- result = idx;
- `).toTransformInto(`
- import { idx } from '@kbn/elastic-idx';
- result = idx;
- `);
- });
-
- it('throws if idx is called with zero arguments', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx();
- `).toThrowTransformError('The `idx` function takes exactly two arguments.');
- });
-
- it('throws if idx is called with one argument', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(1);
- `).toThrowTransformError('The `idx` function takes exactly two arguments.');
- });
-
- it('throws if idx is called with three arguments', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(1, 2, 3);
- `).toThrowTransformError('The `idx` function takes exactly two arguments.');
- });
-
- it('transforms idx calls as part of another expressions', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- paddingStatement();
- a = idx(base, _ => _.b[c]);
- `).toTransformInto(`
- paddingStatement();
- a = base != null && base.b != null ? base.b[c] : undefined;
- `);
- });
-
- it('transforms nested idx calls', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(
- idx(
- idx(base, _ => _.a.b),
- _ => _.c.d
- ),
- _ => _.e.f
- );
- `).toTransformInto(`
- (
- (base != null && base.a != null ? base.a.b : undefined) != null &&
- (base != null && base.a != null ? base.a.b : undefined).c != null ?
- (base != null && base.a != null ? base.a.b : undefined).c.d :
- undefined
- ) != null
- &&
- (
- (base != null && base.a != null ? base.a.b : undefined) != null &&
- (base != null && base.a != null ? base.a.b : undefined).c != null ?
- (base != null && base.a != null ? base.a.b : undefined).c.d :
- undefined
- ).e != null ?
- (
- (base != null && base.a != null ? base.a.b : undefined) != null &&
- (base != null && base.a != null ? base.a.b : undefined).c != null ?
- (base != null && base.a != null ? base.a.b : undefined).c.d :
- undefined
- ).e.f :
- undefined;
- `);
- });
-
- it('transforms idx calls inside async functions (plugin order #1)', () => {
- expect({
- plugins: [babelPluginIdx, transformAsyncToGenerator],
- code: `
- import { idx } from '@kbn/elastic-idx';
- async function f() {
- idx(base, _ => _.b.c.d.e);
- }
- `,
- }).toTransformInto(`
- ${asyncToGeneratorHelperCode}
- function f() {
- return _f.apply(this, arguments);
- }
-
- function _f() {
- _f = _asyncToGenerator(function* () {
- base != null && base.b != null && base.b.c != null && base.b.c.d != null ? base.b.c.d.e : undefined;
- });
- return _f.apply(this, arguments);
- }
- `);
- });
-
- it('transforms idx calls inside async functions (plugin order #2)', () => {
- expect({
- plugins: [transformAsyncToGenerator, babelPluginIdx],
- code: `
- import { idx } from '@kbn/elastic-idx';
- async function f() {
- idx(base, _ => _.b.c.d.e);
- }
- `,
- }).toTransformInto(`
- ${asyncToGeneratorHelperCode}
-
- function f() {
- return _f.apply(this, arguments);
- }
-
- function _f() {
- _f = _asyncToGenerator(function* () {
- base != null && base.b != null && base.b.c != null && base.b.c.d != null ? base.b.c.d.e : undefined;
- });
- return _f.apply(this, arguments);
- }
- `);
- });
-
- it('transforms idx calls in async methods', () => {
- expect({
- plugins: [transformAsyncToGenerator, babelPluginIdx],
- code: `
- import { idx } from '@kbn/elastic-idx';
- class Foo {
- async bar() {
- idx(base, _ => _.b);
- return this;
- }
- }
- `,
- }).toTransformInto(`
- ${asyncToGeneratorHelperCode}
-
- class Foo {
- bar() {
- var _this = this;
-
- return _asyncToGenerator(function* () {
- base != null ? base.b : undefined;
- return _this;
- })();
- }
- }
- `);
- });
-
- it('transforms idx calls when an idx import binding is in scope', () => {
- expect(`
- import idx from '@kbn/elastic-idx';
- idx(base, _ => _.b);
- `).toTransformInto(`
- base != null ? base.b : undefined;
- `);
- });
-
- it('transforms idx calls when an idx const binding is in scope', () => {
- expect(`
- const idx = require('@kbn/elastic-idx');
- idx(base, _ => _.b);
- `).toTransformInto(`
- base != null ? base.b : undefined;
- `);
- });
-
- it('transforms deep idx calls when an idx import binding is in scope', () => {
- expect(`
- import idx from '@kbn/elastic-idx';
- function f() {
- idx(base, _ => _.b);
- }
- `).toTransformInto(`
- function f() {
- base != null ? base.b : undefined;
- }
- `);
- });
-
- it('transforms deep idx calls when an idx const binding is in scope', () => {
- expect(`
- const idx = require('@kbn/elastic-idx');
- function f() {
- idx(base, _ => _.b);
- }
- `).toTransformInto(`
- function f() {
- base != null ? base.b : undefined;
- }
- `);
- });
-
- it('transforms idx calls when an idx is called as a member function on the binding in scope', () => {
- expect(`
- const elastic_idx = require("@kbn/elastic-idx");
- const result = elastic_idx.idx(base, _ => _.a.b.c.d);
- `).toTransformInto(`
- const result = base != null &&
- base.a != null &&
- base.a.b != null &&
- base.a.b.c != null ?
- base.a.b.c.d :
- undefined;
- `);
- });
-
- it('throws on base call expressions', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _().b.c);
- `).toThrowTransformError('idx callbacks may only access properties on the callback parameter.');
- });
-
- it('transforms when the idx parent is a scope creating expression', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- (() => idx(base, _ => _.b));
- `).toTransformInto(`
- () => base != null ? base.b : undefined;
- `);
- });
-
- it('throws if redefined before use', () => {
- expect(`
- let idx = require('@kbn/elastic-idx');
- idx = null;
- idx(base, _ => _.b);
- `).toThrowTransformError('`idx` cannot be redefined.');
- });
-
- it('throws if redefined after use', () => {
- expect(`
- let idx = require('@kbn/elastic-idx');
- idx(base, _ => _.b);
- idx = null;
- `).toThrowTransformError('`idx` cannot be redefined.');
- });
-
- it('throws if there is a duplicate declaration', () => {
- expect(() =>
- transform(`
- let idx = require('@kbn/elastic-idx');
- idx(base, _ => _.b);
- function idx() {}
- `)
- ).toThrow();
- });
-
- it('handles sibling scopes with unique idx', () => {
- expect(`
- function aaa() {
- const idx = require('@kbn/elastic-idx');
- idx(base, _ => _.b);
- }
- function bbb() {
- const idx = require('@kbn/elastic-idx');
- idx(base, _ => _.b);
- }
- `).toTransformInto(`
- function aaa() {
- base != null ? base.b : undefined;
- }
- function bbb() {
- base != null ? base.b : undefined;
- }
- `);
- });
-
- it('handles sibling scopes with and without idx', () => {
- expect(`
- function aaa() {
- const idx = require('@kbn/elastic-idx');
- idx(base, _ => _.b);
- }
- function bbb() {
- idx(base, _ => _.b);
- }
- `).toTransformInto(`
- function aaa() {
- base != null ? base.b : undefined;
- }
- function bbb() {
- idx(base, _ => _.b);
- }
- `);
- });
-
- it('handles nested scopes with shadowing', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _.b);
- function aaa() {
- idx(base, _ => _.b);
- function bbb(idx) {
- idx(base, _ => _.b);
- }
- }
- `).toTransformInto(`
- base != null ? base.b : undefined;
- function aaa() {
- base != null ? base.b : undefined;
- function bbb(idx) {
- idx(base, _ => _.b);
- }
- }
- `);
- });
-
- it('handles named idx import', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- idx(base, _ => _.b);
- `).toTransformInto(`
- base != null ? base.b : undefined;
- `);
- });
-
- it('throws on default plus named import', () => {
- expect(`
- import idx, {foo} from '@kbn/elastic-idx';
- idx(base, _ => _.b);
- `).toThrowTransformError('The idx import must be a single specifier.');
- });
-
- it('throws on default plus namespace import', () => {
- expect(`
- import idx, * as foo from '@kbn/elastic-idx';
- idx(base, _ => _.b);
- `).toThrowTransformError('The idx import must be a single specifier.');
- });
-
- it('throws on named default plus other import', () => {
- expect(`
- import {default as idx, foo} from '@kbn/elastic-idx';
- idx(base, _ => _.b);
- `).toThrowTransformError('The idx import must be a single specifier.');
- });
-
- it('unused idx import should be left alone', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- `).toTransformInto(`
- import { idx } from '@kbn/elastic-idx';
- `);
- });
-
- it('allows configuration of the import name', () => {
- expect({
- code: `
- import { idx } from 'i_d_x';
- idx(base, _ => _.b);
- `,
- options: { importName: 'i_d_x' },
- }).toTransformInto(`
- base != null ? base.b : undefined;
- `);
- });
-
- it('follows configuration of the import name', () => {
- expect({
- code: `
- import { idx } from '@kbn/elastic-idx';
- import { idx as i_d_x } from 'i_d_x';
- i_d_x(base, _ => _.b);
- idx(base, _ => _.c);
- `,
- options: { importName: 'i_d_x' },
- }).toTransformInto(`
- import { idx } from '@kbn/elastic-idx';
-
- base != null ? base.b : undefined;
- idx(base, _ => _.c);
- `);
- });
-
- it('allows configuration of the require name as a string', () => {
- expect({
- code: `
- import { idx } from 'i_d_x';
- idx(base, _ => _.b);
- `,
- options: { importName: 'i_d_x' },
- }).toTransformInto(`
- base != null ? base.b : undefined;
- `);
- });
-
- it('allows configuration of the require name as a RegExp', () => {
- expect({
- code: `
- import { idx } from '../../common/idx';
- idx(base, _ => _.b);
- `,
- options: { importName: /.*idx$/ },
- }).toTransformInto(`
- base != null ? base.b : undefined;
- `);
- });
-
- it('follows configuration of the require name', () => {
- expect({
- code: `
- const idx = require('@kbn/elastic-idx');
- const i_d_x = require('i_d_x');
- i_d_x(base, _ => _.b);
- idx(base, _ => _.c);
- `,
- options: { importName: 'i_d_x' },
- }).toTransformInto(`
- const idx = require('@kbn/elastic-idx');
-
- base != null ? base.b : undefined;
- idx(base, _ => _.c);
- `);
- });
-
- describe('functional', () => {
- it('works with only properties', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- const base = {a: {b: {c: 2}}};
- idx(base, _ => _.a.b.c);
- `).toReturn(2);
- });
-
- it('works with missing properties', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- const base = {a: {b: {}}};
- idx(base, _ => _.a.b.c);
- `).toReturn(undefined);
- });
-
- it('works with null properties', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- const base = {a: {b: null}};
- idx(base, _ => _.a.b.c);
- `).toReturn(undefined);
- });
-
- it('works with nested idx calls', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- const base = {a: {b: {c: {d: {e: {f: 2}}}}}};
- idx(
- idx(
- idx(base, _ => _.a.b),
- _ => _.c.d
- ),
- _ => _.e.f
- );
- `).toReturn(2);
- });
-
- it('works with nested idx calls with missing properties', () => {
- expect(`
- import { idx } from '@kbn/elastic-idx';
- const base = {a: {b: {c: null}}};
- idx(
- idx(
- idx(base, _ => _.a.b),
- _ => _.c.d
- ),
- _ => _.e.f
- );
- `).toReturn(undefined);
- });
- });
-});
diff --git a/packages/kbn-elastic-idx/package.json b/packages/kbn-elastic-idx/package.json
deleted file mode 100644
index 9532983942d6b..0000000000000
--- a/packages/kbn-elastic-idx/package.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "@kbn/elastic-idx",
- "version": "1.0.0",
- "private": true,
- "license": "Apache-2.0",
- "description": "Library for optional chaining & the Babel plugin to transpile idx calls to plain, optimized JS",
- "main": "target/index.js",
- "types": "target/index.d.js",
- "repository": {
- "type": "git",
- "url": "https://github.com/elastic/kibana/tree/master/packages/kbn-elastic-idx"
- },
- "scripts": {
- "build": "tsc",
- "kbn:bootstrap": "yarn build",
- "kbn:watch": "yarn build --watch",
- "test": "jest"
- },
- "devDependencies": {
- "@babel/core": "^7.5.5",
- "@babel/plugin-transform-async-to-generator": "^7.5.0",
- "jest": "^24.9.0",
- "typescript": "3.7.2"
- },
- "jest": {
- "testEnvironment": "node"
- }
-}
diff --git a/packages/kbn-elastic-idx/src/index.ts b/packages/kbn-elastic-idx/src/index.ts
deleted file mode 100644
index eeb0df2747a14..0000000000000
--- a/packages/kbn-elastic-idx/src/index.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * DeepRequiredArray
- * Nested array condition handler
- */
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface DeepRequiredArray extends Array> {}
-
-/**
- * DeepRequiredObject
- * Nested object condition handler
- */
-type DeepRequiredObject = { [P in keyof T]-?: DeepRequired };
-
-/**
- * Function that has deeply required return type
- */
-type FunctionWithRequiredReturnType any> = T extends (
- ...args: infer A
-) => infer R
- ? (...args: A) => DeepRequired
- : never;
-
-/**
- * DeepRequired
- * Required that works for deeply nested structure
- */
-type DeepRequired = NonNullable extends never
- ? T
- : T extends any[]
- ? DeepRequiredArray
- : T extends (...args: any[]) => any
- ? FunctionWithRequiredReturnType
- : NonNullable extends object
- ? DeepRequiredObject>
- : T;
-
-export function idx(
- input: T1,
- accessor: (input: NonNullable>) => T2
-): T2 | undefined {
- try {
- return accessor(input as NonNullable>);
- } catch (error) {
- return undefined;
- }
-}
diff --git a/packages/kbn-elastic-idx/tsconfig.json b/packages/kbn-elastic-idx/tsconfig.json
deleted file mode 100644
index 27833d7594031..0000000000000
--- a/packages/kbn-elastic-idx/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": "../../tsconfig.json",
- "compilerOptions": {
- "declaration": true,
- "outDir": "./target"
- },
- "include": ["src/**/*"]
-}
diff --git a/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/failure_hooks/config.js b/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/failure_hooks/config.js
index 3ff674c89682d..37ea49172d2c4 100644
--- a/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/failure_hooks/config.js
+++ b/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/failure_hooks/config.js
@@ -29,18 +29,19 @@ export default function () {
services: {
hookIntoLIfecycle({ getService }) {
const log = getService('log');
+ const lifecycle = getService('lifecycle')
- getService('lifecycle')
- .on('testFailure', async (err, test) => {
- log.info('testFailure %s %s', err.message, test.fullTitle());
- await delay(10);
- log.info('testFailureAfterDelay %s %s', err.message, test.fullTitle());
- })
- .on('testHookFailure', async (err, test) => {
- log.info('testHookFailure %s %s', err.message, test.fullTitle());
- await delay(10);
- log.info('testHookFailureAfterDelay %s %s', err.message, test.fullTitle());
- });
+ lifecycle.testFailure.add(async (err, test) => {
+ log.info('testFailure %s %s', err.message, test.fullTitle());
+ await delay(10);
+ log.info('testFailureAfterDelay %s %s', err.message, test.fullTitle());
+ });
+
+ lifecycle.testHookFailure.add(async (err, test) => {
+ log.info('testHookFailure %s %s', err.message, test.fullTitle());
+ await delay(10);
+ log.info('testHookFailureAfterDelay %s %s', err.message, test.fullTitle());
+ });
}
},
mochaReporter: {
diff --git a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts
index 459c52997e229..fcba9691b1772 100644
--- a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts
+++ b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts
@@ -18,10 +18,11 @@
*/
import { ToolingLog } from '@kbn/dev-utils';
-import { Suite, Test } from './fake_mocha_types';
+import { Suite, Test } from './fake_mocha_types';
import {
- createLifecycle,
+ Lifecycle,
+ LifecyclePhase,
readConfigFile,
ProviderCollection,
readProviderSpec,
@@ -31,7 +32,7 @@ import {
} from './lib';
export class FunctionalTestRunner {
- public readonly lifecycle = createLifecycle();
+ public readonly lifecycle = new Lifecycle();
private closed = false;
constructor(
@@ -39,13 +40,12 @@ export class FunctionalTestRunner {
private readonly configFile: string,
private readonly configOverrides: any
) {
- this.lifecycle.on('phaseStart', name => {
- log.verbose('starting %j lifecycle phase', name);
- });
-
- this.lifecycle.on('phaseEnd', name => {
- log.verbose('ending %j lifecycle phase', name);
- });
+ for (const [key, value] of Object.entries(this.lifecycle)) {
+ if (value instanceof LifecyclePhase) {
+ value.before$.subscribe(() => log.verbose('starting %j lifecycle phase', key));
+ value.after$.subscribe(() => log.verbose('starting %j lifecycle phase', key));
+ }
+ }
}
async run() {
@@ -59,7 +59,7 @@ export class FunctionalTestRunner {
await providers.loadAll();
const mocha = await setupMocha(this.lifecycle, this.log, config, providers);
- await this.lifecycle.trigger('beforeTests');
+ await this.lifecycle.beforeTests.trigger();
this.log.info('Starting tests');
return await runTests(this.lifecycle, mocha);
@@ -140,6 +140,6 @@ export class FunctionalTestRunner {
if (this.closed) return;
this.closed = true;
- await this.lifecycle.trigger('cleanup');
+ await this.lifecycle.cleanup.trigger();
}
}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/index.ts b/packages/kbn-test/src/functional_test_runner/lib/index.ts
index 88995e9acc5fe..2d354938d7648 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/index.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/index.ts
@@ -17,7 +17,8 @@
* under the License.
*/
-export { createLifecycle, Lifecycle } from './lifecycle';
+export { Lifecycle } from './lifecycle';
+export { LifecyclePhase } from './lifecycle_phase';
export { readConfigFile, Config } from './config';
export { readProviderSpec, ProviderCollection, Provider } from './providers';
export { runTests, setupMocha } from './mocha';
diff --git a/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts b/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts
index 2d9629a436b3a..7f78bc28c6d3d 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts
@@ -17,64 +17,22 @@
* under the License.
*/
-import * as Rx from 'rxjs';
-
-type Listener = (...args: any[]) => Promise | void;
-export type Lifecycle = ReturnType;
-
-export function createLifecycle() {
- const listeners = {
- beforeLoadTests: [] as Listener[],
- beforeTests: [] as Listener[],
- beforeTestSuite: [] as Listener[],
- beforeEachTest: [] as Listener[],
- afterTestSuite: [] as Listener[],
- testFailure: [] as Listener[],
- testHookFailure: [] as Listener[],
- cleanup: [] as Listener[],
- phaseStart: [] as Listener[],
- phaseEnd: [] as Listener[],
- };
-
- const cleanup$ = new Rx.ReplaySubject(1);
-
- return {
- cleanup$: cleanup$.asObservable(),
-
- on(name: keyof typeof listeners, fn: Listener) {
- if (!listeners[name]) {
- throw new TypeError(`invalid lifecycle event "${name}"`);
- }
-
- listeners[name].push(fn);
- return this;
- },
-
- async trigger(name: keyof typeof listeners, ...args: any[]) {
- if (!listeners[name]) {
- throw new TypeError(`invalid lifecycle event "${name}"`);
- }
-
- if (name === 'cleanup') {
- if (cleanup$.closed) {
- return;
- }
-
- cleanup$.next();
- cleanup$.complete();
- }
-
- try {
- if (name !== 'phaseStart' && name !== 'phaseEnd') {
- await this.trigger('phaseStart', name);
- }
-
- await Promise.all(listeners[name].map(async fn => await fn(...args)));
- } finally {
- if (name !== 'phaseStart' && name !== 'phaseEnd') {
- await this.trigger('phaseEnd', name);
- }
- }
- },
- };
+import { LifecyclePhase } from './lifecycle_phase';
+
+// mocha's global types mean we can't import Mocha or it will override the global jest types..............
+type ItsASuite = any;
+type ItsATest = any;
+
+export class Lifecycle {
+ public readonly beforeTests = new LifecyclePhase<[]>({
+ singular: true,
+ });
+ public readonly beforeTestSuite = new LifecyclePhase<[ItsASuite]>();
+ public readonly beforeEachTest = new LifecyclePhase<[ItsATest]>();
+ public readonly afterTestSuite = new LifecyclePhase<[ItsASuite]>();
+ public readonly testFailure = new LifecyclePhase<[Error, ItsATest]>();
+ public readonly testHookFailure = new LifecyclePhase<[Error, ItsATest]>();
+ public readonly cleanup = new LifecyclePhase<[]>({
+ singular: true,
+ });
}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/lifecycle_phase.test.ts b/packages/kbn-test/src/functional_test_runner/lib/lifecycle_phase.test.ts
new file mode 100644
index 0000000000000..94dd76884f2ca
--- /dev/null
+++ b/packages/kbn-test/src/functional_test_runner/lib/lifecycle_phase.test.ts
@@ -0,0 +1,206 @@
+/*
+ * 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 Rx from 'rxjs';
+import { materialize, toArray } from 'rxjs/operators';
+
+import { LifecyclePhase } from './lifecycle_phase';
+
+describe('with randomness', () => {
+ beforeEach(() => {
+ const randomOrder = [0, 0.75, 0.5, 0.25, 1];
+ jest.spyOn(Math, 'random').mockImplementation(() => {
+ const n = randomOrder.shift()!;
+ randomOrder.push(n);
+ return n;
+ });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('calls handlers in random order', async () => {
+ const phase = new LifecyclePhase();
+ const order: string[] = [];
+
+ phase.add(
+ jest.fn(() => {
+ order.push('one');
+ })
+ );
+
+ phase.add(
+ jest.fn(() => {
+ order.push('two');
+ })
+ );
+
+ phase.add(
+ jest.fn(() => {
+ order.push('three');
+ })
+ );
+
+ await phase.trigger();
+ expect(order).toMatchInlineSnapshot(`
+ Array [
+ "one",
+ "three",
+ "two",
+ ]
+ `);
+ });
+});
+
+describe('without randomness', () => {
+ beforeEach(() => jest.spyOn(Math, 'random').mockImplementation(() => 0));
+ afterEach(() => jest.restoreAllMocks());
+
+ it('calls all handlers and throws first error', async () => {
+ const phase = new LifecyclePhase();
+ const fn1 = jest.fn();
+ phase.add(fn1);
+
+ const fn2 = jest.fn(() => {
+ throw new Error('foo');
+ });
+ phase.add(fn2);
+
+ const fn3 = jest.fn();
+ phase.add(fn3);
+
+ await expect(phase.trigger()).rejects.toThrowErrorMatchingInlineSnapshot(`"foo"`);
+ expect(fn1).toHaveBeenCalled();
+ expect(fn2).toHaveBeenCalled();
+ expect(fn3).toHaveBeenCalled();
+ });
+
+ it('triggers before$ just before calling handler and after$ once it resolves', async () => {
+ const phase = new LifecyclePhase();
+ const order: string[] = [];
+
+ const beforeSub = jest.fn(() => order.push('before'));
+ phase.before$.subscribe(beforeSub);
+
+ const afterSub = jest.fn(() => order.push('after'));
+ phase.after$.subscribe(afterSub);
+
+ const handler = jest.fn(async () => {
+ order.push('handler start');
+ await new Promise(resolve => setTimeout(resolve, 100));
+ order.push('handler done');
+ });
+ phase.add(handler);
+
+ await phase.trigger();
+ expect(order).toMatchInlineSnapshot(`
+ Array [
+ "before",
+ "handler start",
+ "handler done",
+ "after",
+ ]
+ `);
+ });
+
+ it('completes before$ and after$ if phase is singular', async () => {
+ const phase = new LifecyclePhase({ singular: true });
+
+ const beforeNotifs: Array> = [];
+ phase.before$.pipe(materialize()).subscribe(n => beforeNotifs.push(n));
+
+ const afterNotifs: Array> = [];
+ phase.after$.pipe(materialize()).subscribe(n => afterNotifs.push(n));
+
+ await phase.trigger();
+ expect(beforeNotifs).toMatchInlineSnapshot(`
+ Array [
+ Notification {
+ "error": undefined,
+ "hasValue": true,
+ "kind": "N",
+ "value": undefined,
+ },
+ Notification {
+ "error": undefined,
+ "hasValue": false,
+ "kind": "C",
+ "value": undefined,
+ },
+ ]
+ `);
+ expect(afterNotifs).toMatchInlineSnapshot(`
+ Array [
+ Notification {
+ "error": undefined,
+ "hasValue": true,
+ "kind": "N",
+ "value": undefined,
+ },
+ Notification {
+ "error": undefined,
+ "hasValue": false,
+ "kind": "C",
+ "value": undefined,
+ },
+ ]
+ `);
+ });
+
+ it('completes before$ subscribers after trigger of singular phase', async () => {
+ const phase = new LifecyclePhase({ singular: true });
+ await phase.trigger();
+
+ await expect(phase.before$.pipe(materialize(), toArray()).toPromise()).resolves
+ .toMatchInlineSnapshot(`
+ Array [
+ Notification {
+ "error": undefined,
+ "hasValue": false,
+ "kind": "C",
+ "value": undefined,
+ },
+ ]
+ `);
+ });
+
+ it('replays after$ event subscribers after trigger of singular phase', async () => {
+ const phase = new LifecyclePhase({ singular: true });
+ await phase.trigger();
+
+ await expect(phase.after$.pipe(materialize(), toArray()).toPromise()).resolves
+ .toMatchInlineSnapshot(`
+ Array [
+ Notification {
+ "error": undefined,
+ "hasValue": true,
+ "kind": "N",
+ "value": undefined,
+ },
+ Notification {
+ "error": undefined,
+ "hasValue": false,
+ "kind": "C",
+ "value": undefined,
+ },
+ ]
+ `);
+ });
+});
diff --git a/packages/kbn-test/src/functional_test_runner/lib/lifecycle_phase.ts b/packages/kbn-test/src/functional_test_runner/lib/lifecycle_phase.ts
new file mode 100644
index 0000000000000..5c7fdb532faa1
--- /dev/null
+++ b/packages/kbn-test/src/functional_test_runner/lib/lifecycle_phase.ts
@@ -0,0 +1,82 @@
+/*
+ * 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 Rx from 'rxjs';
+
+const shuffle = (arr: T[]) => arr.slice().sort(() => (Math.random() > 0.5 ? 1 : -1));
+
+export type GetArgsType> = T extends LifecyclePhase
+ ? X
+ : never;
+
+export class LifecyclePhase {
+ private readonly handlers: Array<(...args: Args) => Promise | void> = [];
+
+ private readonly beforeSubj = new Rx.Subject();
+ public readonly before$ = this.beforeSubj.asObservable();
+
+ private readonly afterSubj = this.options.singular
+ ? new Rx.ReplaySubject(1)
+ : new Rx.Subject();
+ public readonly after$ = this.afterSubj.asObservable();
+
+ constructor(
+ private readonly options: {
+ singular?: boolean;
+ } = {}
+ ) {}
+
+ public add(fn: (...args: Args) => Promise | void) {
+ this.handlers.push(fn);
+ }
+
+ public async trigger(...args: Args) {
+ if (this.beforeSubj.isStopped) {
+ throw new Error(`singular lifecycle event can only be triggered once`);
+ }
+
+ this.beforeSubj.next(undefined);
+ if (this.options.singular) {
+ this.beforeSubj.complete();
+ }
+
+ // catch the first error but still execute all handlers
+ let error;
+
+ // shuffle the handlers to prevent relying on their order
+ for (const fn of shuffle(this.handlers)) {
+ try {
+ await fn(...args);
+ } catch (_error) {
+ if (!error) {
+ error = _error;
+ }
+ }
+ }
+
+ this.afterSubj.next(undefined);
+ if (this.options.singular) {
+ this.afterSubj.complete();
+ }
+
+ if (error) {
+ throw error;
+ }
+ }
+}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js
index e65eb2f27d063..4eb45229c2234 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js
@@ -58,7 +58,7 @@ export function decorateMochaUi(lifecycle, context) {
argumentsList[1] = function() {
before(async () => {
- await lifecycle.trigger('beforeTestSuite', this);
+ await lifecycle.beforeTestSuite.trigger(this);
});
this.tags = tags => {
@@ -68,7 +68,7 @@ export function decorateMochaUi(lifecycle, context) {
provider.call(this);
after(async () => {
- await lifecycle.trigger('afterTestSuite', this);
+ await lifecycle.afterTestSuite.trigger(this);
});
};
@@ -94,7 +94,7 @@ export function decorateMochaUi(lifecycle, context) {
return wrapNonSuiteFunction(
name,
wrapRunnableArgsWithErrorHandler(fn, async (err, test) => {
- await lifecycle.trigger('testFailure', err, test);
+ await lifecycle.testFailure.trigger(err, test);
})
);
}
@@ -112,7 +112,7 @@ export function decorateMochaUi(lifecycle, context) {
return wrapNonSuiteFunction(
name,
wrapRunnableArgsWithErrorHandler(fn, async (err, test) => {
- await lifecycle.trigger('testHookFailure', err, test);
+ await lifecycle.testHookFailure.trigger(err, test);
})
);
}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/run_tests.ts b/packages/kbn-test/src/functional_test_runner/lib/mocha/run_tests.ts
index 2d98052b1062a..654f588fda858 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/mocha/run_tests.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/run_tests.ts
@@ -35,7 +35,7 @@ export async function runTests(lifecycle: Lifecycle, mocha: Mocha) {
runComplete = true;
});
- lifecycle.on('cleanup', () => {
+ lifecycle.cleanup.add(() => {
if (!runComplete) runner.abort();
});
diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js
index a425251a29f36..326877919d985 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js
@@ -41,7 +41,7 @@ export async function setupMocha(lifecycle, log, config, providers) {
// global beforeEach hook in root suite triggers before all others
mocha.suite.beforeEach('global before each', async function() {
- await lifecycle.trigger('beforeEachTest', this.currentTest);
+ await lifecycle.beforeEachTest.trigger(this.currentTest);
});
loadTestFiles({
diff --git a/packages/kbn-ui-framework/dist/kui_dark.css b/packages/kbn-ui-framework/dist/kui_dark.css
index dcbd65fbca520..aa16bcdb34d36 100644
--- a/packages/kbn-ui-framework/dist/kui_dark.css
+++ b/packages/kbn-ui-framework/dist/kui_dark.css
@@ -1,10 +1,24 @@
+/* 1 */
+/* 1 */
+/**
+ * 1. Extend beta badges to at least 40% of the container's width
+ * 2. Fix for IE to ensure badges are visible outside of a tag
+ */
+/**
+ * 1. Apply margin to all but last item in the flex.
+ * 2. Margin gets flipped because of the row-reverse.
+ */
/**
- * 2. Account for inner box-shadow style border when in group
* 3. Must supply both values to background-size or some browsers apply the single value to both directions
*/
/**
* 4. Override invalid state with focus state.
*/
+/**
+ * Mixin for use in:
+ * - EuiCard
+ * - EuiPageContent
+*/
/**
* 1. Enforce pointer when there's no href.
* 2. Allow these styles to be applied to a button element.
@@ -1595,7 +1609,6 @@ main {
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
- height: 100%;
padding: 12px 8px;
font-size: 16px;
font-weight: bold;
diff --git a/packages/kbn-ui-framework/dist/kui_light.css b/packages/kbn-ui-framework/dist/kui_light.css
index 3e82873d53aa7..9b42bbb517f46 100644
--- a/packages/kbn-ui-framework/dist/kui_light.css
+++ b/packages/kbn-ui-framework/dist/kui_light.css
@@ -1,10 +1,24 @@
+/* 1 */
+/* 1 */
+/**
+ * 1. Extend beta badges to at least 40% of the container's width
+ * 2. Fix for IE to ensure badges are visible outside of a tag
+ */
+/**
+ * 1. Apply margin to all but last item in the flex.
+ * 2. Margin gets flipped because of the row-reverse.
+ */
/**
- * 2. Account for inner box-shadow style border when in group
* 3. Must supply both values to background-size or some browsers apply the single value to both directions
*/
/**
* 4. Override invalid state with focus state.
*/
+/**
+ * Mixin for use in:
+ * - EuiCard
+ * - EuiPageContent
+*/
/**
* 1. Enforce pointer when there's no href.
* 2. Allow these styles to be applied to a button element.
@@ -522,7 +536,7 @@ main {
-webkit-appearance: none;
/* 1 */
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
width: 16px;
height: 16px;
@@ -623,7 +637,7 @@ main {
line-height: 1.5;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
-webkit-transition: border-color 0.1s linear;
transition: border-color 0.1s linear;
@@ -662,7 +676,7 @@ main {
line-height: 1.5;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
-webkit-transition: border-color 0.1s linear;
transition: border-color 0.1s linear;
@@ -734,7 +748,7 @@ main {
line-height: 1.5;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
-webkit-transition: border-color 0.1s linear;
transition: border-color 0.1s linear;
@@ -777,7 +791,7 @@ main {
line-height: 1.5;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
-webkit-transition: border-color 0.1s linear;
transition: border-color 0.1s linear;
@@ -1252,7 +1266,7 @@ main {
font-size: 14px;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px; }
.kuiLocalDropdownInput:focus {
border-color: #006BB4; }
@@ -1410,7 +1424,7 @@ main {
line-height: 1.5;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
-webkit-transition: border-color 0.1s linear;
transition: border-color 0.1s linear;
@@ -1491,7 +1505,7 @@ main {
line-height: 1.5;
color: #343741;
background-color: #fbfcfd;
- border: 1px solid rgba(0, 0, 0, 0.1);
+ border: 1px solid rgba(15, 39, 118, 0.1);
border-radius: 4px;
-webkit-transition: border-color 0.1s linear;
transition: border-color 0.1s linear;
@@ -1595,7 +1609,6 @@ main {
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
- height: 100%;
padding: 12px 8px;
font-size: 16px;
font-weight: bold;
diff --git a/packages/kbn-ui-framework/src/kui_dark.scss b/packages/kbn-ui-framework/src/kui_dark.scss
index 2bfbdbb4147ce..aa9ba0f1bee70 100644
--- a/packages/kbn-ui-framework/src/kui_dark.scss
+++ b/packages/kbn-ui-framework/src/kui_dark.scss
@@ -3,8 +3,6 @@
@import '../../../node_modules/@elastic/eui/src/global_styling/functions/index';
@import '../../../node_modules/@elastic/eui/src/global_styling/variables/index';
@import '../../../node_modules/@elastic/eui/src/global_styling/mixins/index';
-@import '../../../node_modules/@elastic/eui/src/components/form/variables';
-@import '../../../node_modules/@elastic/eui/src/components/form/mixins';
// Configuration
@import 'global_styling/variables/index';
diff --git a/packages/kbn-ui-framework/src/kui_light.scss b/packages/kbn-ui-framework/src/kui_light.scss
index d4288be27ef75..b912b6e217882 100644
--- a/packages/kbn-ui-framework/src/kui_light.scss
+++ b/packages/kbn-ui-framework/src/kui_light.scss
@@ -3,8 +3,6 @@
@import '../../../node_modules/@elastic/eui/src/global_styling/functions/index';
@import '../../../node_modules/@elastic/eui/src/global_styling/variables/index';
@import '../../../node_modules/@elastic/eui/src/global_styling/mixins/index';
-@import '../../../node_modules/@elastic/eui/src/components/form/variables';
-@import '../../../node_modules/@elastic/eui/src/components/form/mixins';
// Configuration
@import 'global_styling/variables/index';
diff --git a/packages/kbn-utility-types/README.md b/packages/kbn-utility-types/README.md
index ff6c7c7268a15..9707ff5a1ed9c 100644
--- a/packages/kbn-utility-types/README.md
+++ b/packages/kbn-utility-types/README.md
@@ -18,7 +18,9 @@ type B = UnwrapPromise; // string
## Reference
-- `UnwrapPromise` — Returns wrapped type of a promise.
-- `UnwrapObservable` — Returns wrapped type of an observable.
-- `ShallowPromise` — Same as `Promise` type, but it flat maps the wrapped type.
+- `Ensure` — Makes sure `T` is of type `X`.
- `ObservableLike` — Minimal interface for an object resembling an `Observable`.
+- `RecursiveReadonly` — Like `Readonly`, but freezes object recursively.
+- `ShallowPromise` — Same as `Promise` type, but it flat maps the wrapped type.
+- `UnwrapObservable` — Returns wrapped type of an observable.
+- `UnwrapPromise` — Returns wrapped type of a promise.
diff --git a/packages/kbn-utility-types/index.ts b/packages/kbn-utility-types/index.ts
index f17890528bfd2..495b5fb374b43 100644
--- a/packages/kbn-utility-types/index.ts
+++ b/packages/kbn-utility-types/index.ts
@@ -42,3 +42,19 @@ export type UnwrapObservable> = T extends Observab
* Converts a type to a `Promise`, unless it is already a `Promise`. Useful when proxying the return value of a possibly async function.
*/
export type ShallowPromise = T extends Promise ? Promise : Promise;
+
+/**
+ * Ensures T is of type X.
+ */
+export type Ensure = T extends X ? T : never;
+
+// If we define this inside RecursiveReadonly TypeScript complains.
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+interface RecursiveReadonlyArray extends Array> {}
+export type RecursiveReadonly = T extends (...args: any) => any
+ ? T
+ : T extends any[]
+ ? RecursiveReadonlyArray
+ : T extends object
+ ? Readonly<{ [K in keyof T]: RecursiveReadonly }>
+ : T;
diff --git a/src/cli/cluster/cluster_manager.js b/src/cli/cluster/cluster_manager.js
index 8ddeda93e6a7e..050d13b4b2c3e 100644
--- a/src/cli/cluster/cluster_manager.js
+++ b/src/cli/cluster/cluster_manager.js
@@ -90,6 +90,18 @@ export default class ClusterManager {
});
});
+ // When receive that event from server worker
+ // forward a reloadLoggingConfig message to master
+ // and all workers. This is only used by LogRotator service
+ // when the cluster mode is enabled
+ this.server.on('reloadLoggingConfigFromServerWorker', () => {
+ process.emit('message', { reloadLoggingConfig: true });
+
+ this.workers.forEach(worker => {
+ worker.fork.send({ reloadLoggingConfig: true });
+ });
+ });
+
bindAll(this, 'onWatcherAdd', 'onWatcherError', 'onWatcherChange');
if (opts.open) {
diff --git a/src/cli/cluster/worker.js b/src/cli/cluster/worker.js
index 4d9aba93d61db..254cce483cb7c 100644
--- a/src/cli/cluster/worker.js
+++ b/src/cli/cluster/worker.js
@@ -134,6 +134,9 @@ export default class Worker extends EventEmitter {
this.listening = true;
this.emit('listening');
break;
+ case 'RELOAD_LOGGING_CONFIG_FROM_SERVER_WORKER':
+ this.emit('reloadLoggingConfigFromServerWorker');
+ break;
}
}
diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md
index eb9a66e99f0aa..2527ffba2cbbd 100644
--- a/src/core/MIGRATION.md
+++ b/src/core/MIGRATION.md
@@ -1193,7 +1193,7 @@ import { setup, start } from '../core_plugins/visualizations/public/legacy';
| Legacy Platform | New Platform | Notes |
| ------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| `import 'ui/apply_filters'` | `import { applyFiltersPopover } from '../data/public'` | Directive is deprecated. |
+| `import 'ui/apply_filters'` | N/A. Replaced by triggering an APPLY_FILTER_TRIGGER trigger. | Directive is deprecated. |
| `import 'ui/filter_bar'` | `import { FilterBar } from '../data/public'` | Directive is deprecated. |
| `import 'ui/query_bar'` | `import { QueryStringInput } from '../data/public'` | Directives are deprecated. |
| `import 'ui/search_bar'` | `import { SearchBar } from '../data/public'` | Directive is deprecated. |
@@ -1225,6 +1225,7 @@ In server code, `core` can be accessed from either `server.newPlatform` or `kbnS
| `request.getBasePath()` | [`core.http.basePath.get`](/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md) | |
| `server.plugins.elasticsearch.getCluster('data')` | [`core.elasticsearch.dataClient$`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md) | Handlers will also include a pre-configured client |
| `server.plugins.elasticsearch.getCluster('admin')` | [`core.elasticsearch.adminClient$`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md) | Handlers will also include a pre-configured client |
+| `xpackMainPlugin.info.feature(pluginID).registerLicenseCheckResultsGenerator` | [`x-pack licensing plugin`](/x-pack/plugins/licensing/README.md) | |
_See also: [Server's CoreSetup API Docs](/docs/development/core/server/kibana-plugin-server.coresetup.md)_
diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts
index 6313a27b6b821..a031ab6070413 100644
--- a/src/core/public/application/types.ts
+++ b/src/core/public/application/types.ts
@@ -30,6 +30,7 @@ import { OverlayStart } from '../overlays';
import { PluginOpaqueId } from '../plugins';
import { IUiSettingsClient } from '../ui_settings';
import { RecursiveReadonly } from '../../utils';
+import { SavedObjectsStart } from '../saved_objects';
/** @public */
export interface AppBase {
@@ -118,6 +119,8 @@ export interface AppMountContext {
notifications: NotificationsStart;
/** {@link OverlayStart} */
overlays: OverlayStart;
+ /** {@link SavedObjectsStart} */
+ savedObjects: SavedObjectsStart;
/** {@link IUiSettingsClient} */
uiSettings: IUiSettingsClient;
/**
diff --git a/src/core/public/chrome/constants.ts b/src/core/public/chrome/constants.ts
index 8fcf3e6d62231..9c76e2b1ee84e 100644
--- a/src/core/public/chrome/constants.ts
+++ b/src/core/public/chrome/constants.ts
@@ -17,6 +17,8 @@
* under the License.
*/
-export const KIBANA_FEEDBACK_LINK = 'https://www.elastic.co/products/kibana/feedback';
-export const KIBANA_ASK_ELASTIC_LINK = 'https://www.elastic.co/products/kibana/ask-elastic';
+export const KIBANA_FEEDBACK_LINK =
+ 'https://www.elastic.co/products/kibana/feedback?blade=kibanafeedback';
+export const KIBANA_ASK_ELASTIC_LINK =
+ 'https://www.elastic.co/products/kibana/ask-elastic?blade=kibanaaskelastic';
export const GITHUB_CREATE_ISSUE_LINK = 'https://github.com/elastic/kibana/issues/new/choose';
diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts
index 2404459ad1383..4818484b00819 100644
--- a/src/core/public/core_system.ts
+++ b/src/core/public/core_system.ts
@@ -255,6 +255,7 @@ export class CoreSystem {
i18n,
notifications,
overlays,
+ savedObjects,
uiSettings,
injectedMetadata: pick(injectedMetadata, ['getInjectedVar']),
}));
diff --git a/src/core/public/http/http_service.mock.ts b/src/core/public/http/http_service.mock.ts
index fe7c749091b03..5887e7b3e96d0 100644
--- a/src/core/public/http/http_service.mock.ts
+++ b/src/core/public/http/http_service.mock.ts
@@ -21,10 +21,10 @@ import { HttpService } from './http_service';
import { HttpSetup } from './types';
import { BehaviorSubject } from 'rxjs';
import { BasePath } from './base_path_service';
-import { AnonymousPaths } from './anonymous_paths';
export type HttpSetupMock = jest.Mocked & {
basePath: BasePath;
+ anonymousPaths: jest.Mocked;
};
const createServiceMock = ({ basePath = '' } = {}): HttpSetupMock => ({
@@ -37,7 +37,10 @@ const createServiceMock = ({ basePath = '' } = {}): HttpSetupMock => ({
delete: jest.fn(),
options: jest.fn(),
basePath: new BasePath(basePath),
- anonymousPaths: new AnonymousPaths(new BasePath(basePath)),
+ anonymousPaths: {
+ register: jest.fn(),
+ isAnonymous: jest.fn(),
+ },
addLoadingCount: jest.fn(),
getLoadingCount$: jest.fn().mockReturnValue(new BehaviorSubject(0)),
stop: jest.fn(),
diff --git a/src/core/public/i18n/i18n_eui_mapping.tsx b/src/core/public/i18n/i18n_eui_mapping.tsx
new file mode 100644
index 0000000000000..4c7cdd18d03f6
--- /dev/null
+++ b/src/core/public/i18n/i18n_eui_mapping.tsx
@@ -0,0 +1,574 @@
+/*
+ * 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 React from 'react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+interface EuiValues {
+ [key: string]: any;
+}
+
+export const euiContextMapping = {
+ 'euiBasicTable.selectAllRows': i18n.translate('core.euiBasicTable.selectAllRows', {
+ defaultMessage: 'Select all rows',
+ description: 'ARIA and displayed label on a checkbox to select all table rows',
+ }),
+ 'euiBasicTable.selectThisRow': i18n.translate('core.euiBasicTable.selectThisRow', {
+ defaultMessage: 'Select this row',
+ description: 'ARIA and displayed label on a checkbox to select a single table row',
+ }),
+ 'euiBasicTable.tableDescription': ({ itemCount }: EuiValues) =>
+ i18n.translate('core.euiBasicTable.tableDescription', {
+ defaultMessage: 'Below is a table of {itemCount} items.',
+ values: { itemCount },
+ description: 'Screen reader text to describe the size of a table',
+ }),
+ 'euiBottomBar.screenReaderAnnouncement': i18n.translate(
+ 'core.euiBottomBar.screenReaderAnnouncement',
+ {
+ defaultMessage:
+ 'There is a new menu opening with page level controls at the end of the document.',
+ description:
+ 'Screen reader announcement that functionality is available in the page document',
+ }
+ ),
+ 'euiBreadcrumbs.collapsedBadge.ariaLabel': i18n.translate(
+ 'core.euiBreadcrumbs.collapsedBadge.ariaLabel',
+ {
+ defaultMessage: 'Show all breadcrumbs',
+ description: 'Displayed when one or more breadcrumbs are hidden.',
+ }
+ ),
+ 'euiCardSelect.select': i18n.translate('core.euiCardSelect.select', {
+ defaultMessage: 'Select',
+ description: 'Displayed button text when a card option can be selected.',
+ }),
+ 'euiCardSelect.selected': i18n.translate('core.euiCardSelect.selected', {
+ defaultMessage: 'Selected',
+ description: 'Displayed button text when a card option is selected.',
+ }),
+ 'euiCardSelect.unavailable': i18n.translate('core.euiCardSelect.unavailable', {
+ defaultMessage: 'Unavailable',
+ description: 'Displayed button text when a card option is unavailable.',
+ }),
+ 'euiCodeBlock.copyButton': i18n.translate('core.euiCodeBlock.copyButton', {
+ defaultMessage: 'Copy',
+ description: 'ARIA label for a button that copies source code text to the clipboard',
+ }),
+ 'euiCodeEditor.startEditing': i18n.translate('core.euiCodeEditor.startEditing', {
+ defaultMessage: 'Press Enter to start editing.',
+ }),
+ 'euiCodeEditor.startInteracting': i18n.translate('core.euiCodeEditor.startInteracting', {
+ defaultMessage: 'Press Enter to start interacting with the code.',
+ }),
+ 'euiCodeEditor.stopEditing': i18n.translate('core.euiCodeEditor.stopEditing', {
+ defaultMessage: "When you're done, press Escape to stop editing.",
+ }),
+ 'euiCodeEditor.stopInteracting': i18n.translate('core.euiCodeEditor.stopInteracting', {
+ defaultMessage: "When you're done, press Escape to stop interacting with the code.",
+ }),
+ 'euiCollapsedItemActions.allActions': i18n.translate('core.euiCollapsedItemActions.allActions', {
+ defaultMessage: 'All actions',
+ description: 'ARIA label and tooltip content describing a button that expands an actions menu',
+ }),
+ 'euiColorPicker.screenReaderAnnouncement': i18n.translate(
+ 'core.euiColorPicker.screenReaderAnnouncement',
+ {
+ defaultMessage:
+ 'A popup with a range of selectable colors opened. Tab forward to cycle through colors choices or press escape to close this popup.',
+ description:
+ 'Message when the color picker popover is opened. Describes the interaction with the elements in the popover.',
+ }
+ ),
+ 'euiColorPicker.swatchAriaLabel': ({ swatch }: EuiValues) =>
+ i18n.translate('core.euiColorPicker.swatchAriaLabel', {
+ defaultMessage: 'Select {swatch} as the color',
+ values: { swatch },
+ description:
+ 'Screen reader text to describe the action and hex value of the selectable option',
+ }),
+ 'euiColorStopThumb.removeLabel': i18n.translate('core.euiColorStopThumb.removeLabel', {
+ defaultMessage: 'Remove this stop',
+ description: 'Label accompanying a button whose action will remove the color stop',
+ }),
+ 'euiColorStopThumb.screenReaderAnnouncement': i18n.translate(
+ 'core.euiColorStopThumb.screenReaderAnnouncement',
+ {
+ defaultMessage:
+ 'A popup with a color stop edit form opened. Tab forward to cycle through form controls or press escape to close this popup.',
+ description:
+ 'Message when the color picker popover has opened for an individual color stop thumb.',
+ }
+ ),
+ 'euiColorStops.screenReaderAnnouncement': ({ label, readOnly, disabled }: EuiValues) =>
+ i18n.translate('core.euiColorStops.screenReaderAnnouncement', {
+ defaultMessage:
+ '{label}: {readOnly} {disabled} Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop.',
+ values: { label, readOnly, disabled },
+ description:
+ 'Screen reader text to describe the composite behavior of the color stops component.',
+ }),
+ 'euiColumnSelector.hideAll': i18n.translate('core.euiColumnSelector.hideAll', {
+ defaultMessage: 'Hide all',
+ }),
+ 'euiColumnSelector.selectAll': i18n.translate('core.euiColumnSelector.selectAll', {
+ defaultMessage: 'Show all',
+ }),
+ 'euiColumnSorting.clearAll': i18n.translate('core.euiColumnSorting.clearAll', {
+ defaultMessage: 'Clear sorting',
+ }),
+ 'euiColumnSorting.emptySorting': i18n.translate('core.euiColumnSorting.emptySorting', {
+ defaultMessage: 'Currently no fields are sorted',
+ }),
+ 'euiColumnSorting.pickFields': i18n.translate('core.euiColumnSorting.pickFields', {
+ defaultMessage: 'Pick fields to sort by',
+ }),
+ 'euiColumnSorting.sortFieldAriaLabel': i18n.translate(
+ 'core.euiColumnSorting.sortFieldAriaLabel',
+ {
+ defaultMessage: 'Sort by:',
+ }
+ ),
+ 'euiColumnSortingDraggable.activeSortLabel': i18n.translate(
+ 'core.euiColumnSortingDraggable.activeSortLabel',
+ {
+ defaultMessage: 'is sorting this data grid',
+ }
+ ),
+ 'euiColumnSortingDraggable.defaultSortAsc': i18n.translate(
+ 'core.euiColumnSortingDraggable.defaultSortAsc',
+ {
+ defaultMessage: 'A-Z',
+ description: 'Ascending sort label',
+ }
+ ),
+ 'euiColumnSortingDraggable.defaultSortDesc': i18n.translate(
+ 'core.euiColumnSortingDraggable.defaultSortDesc',
+ {
+ defaultMessage: 'Z-A',
+ description: 'Descending sort label',
+ }
+ ),
+ 'euiColumnSortingDraggable.removeSortLabel': i18n.translate(
+ 'core.euiColumnSortingDraggable.removeSortLabel',
+ {
+ defaultMessage: 'Remove from data grid sort:',
+ }
+ ),
+ 'euiColumnSortingDraggable.toggleLegend': i18n.translate(
+ 'core.euiColumnSortingDraggable.toggleLegend',
+ {
+ defaultMessage: 'Select sorting method for field:',
+ }
+ ),
+ 'euiComboBoxOptionsList.allOptionsSelected': i18n.translate(
+ 'core.euiComboBoxOptionsList.allOptionsSelected',
+ {
+ defaultMessage: "You've selected all available options",
+ }
+ ),
+ 'euiComboBoxOptionsList.alreadyAdded': ({ label }: EuiValues) => (
+
+ ),
+ 'euiComboBoxOptionsList.createCustomOption': ({ key, searchValue }: EuiValues) => (
+
+ ),
+ 'euiComboBoxOptionsList.loadingOptions': i18n.translate(
+ 'core.euiComboBoxOptionsList.loadingOptions',
+ {
+ defaultMessage: 'Loading options',
+ description: 'Placeholder message while data is asynchronously loaded',
+ }
+ ),
+ 'euiComboBoxOptionsList.noAvailableOptions': i18n.translate(
+ 'core.euiComboBoxOptionsList.noAvailableOptions',
+ {
+ defaultMessage: "There aren't any options available",
+ }
+ ),
+ 'euiComboBoxOptionsList.noMatchingOptions': ({ searchValue }: EuiValues) => (
+
+ ),
+ 'euiComboBoxPill.removeSelection': ({ children }: EuiValues) =>
+ i18n.translate('core.euiComboBoxPill.removeSelection', {
+ defaultMessage: 'Remove {children} from selection in this group',
+ values: { children },
+ description: 'ARIA label, `children` is the human-friendly value of an option',
+ }),
+ 'euiCommonlyUsedTimeRanges.legend': i18n.translate('core.euiCommonlyUsedTimeRanges.legend', {
+ defaultMessage: 'Commonly used',
+ }),
+ 'euiDataGrid.screenReaderNotice': i18n.translate('core.euiDataGrid.screenReaderNotice', {
+ defaultMessage: 'Cell contains interactive content.',
+ }),
+ 'euiDataGridCell.expandButtonTitle': i18n.translate('core.euiDataGridCell.expandButtonTitle', {
+ defaultMessage: 'Click or hit enter to interact with cell content',
+ }),
+ 'euiDataGridSchema.booleanSortTextAsc': i18n.translate(
+ 'core.euiDataGridSchema.booleanSortTextAsc',
+ {
+ defaultMessage: 'True-False',
+ description: 'Ascending boolean label',
+ }
+ ),
+ 'euiDataGridSchema.booleanSortTextDesc': i18n.translate(
+ 'core.euiDataGridSchema.booleanSortTextDesc',
+ {
+ defaultMessage: 'False-True',
+ description: 'Descending boolean label',
+ }
+ ),
+ 'euiDataGridSchema.currencySortTextAsc': i18n.translate(
+ 'core.euiDataGridSchema.currencySortTextAsc',
+ {
+ defaultMessage: 'Low-High',
+ description: 'Ascending currency label',
+ }
+ ),
+ 'euiDataGridSchema.currencySortTextDesc': i18n.translate(
+ 'core.euiDataGridSchema.currencySortTextDesc',
+ {
+ defaultMessage: 'High-Low',
+ description: 'Descending currency label',
+ }
+ ),
+ 'euiDataGridSchema.dateSortTextAsc': i18n.translate('core.euiDataGridSchema.dateSortTextAsc', {
+ defaultMessage: 'New-Old',
+ description: 'Ascending date label',
+ }),
+ 'euiDataGridSchema.dateSortTextDesc': i18n.translate('core.euiDataGridSchema.dateSortTextDesc', {
+ defaultMessage: 'Old-New',
+ description: 'Descending date label',
+ }),
+ 'euiDataGridSchema.numberSortTextAsc': i18n.translate(
+ 'core.euiDataGridSchema.numberSortTextAsc',
+ {
+ defaultMessage: 'Low-High',
+ description: 'Ascending number label',
+ }
+ ),
+ 'euiDataGridSchema.numberSortTextDesc': i18n.translate(
+ 'core.euiDataGridSchema.numberSortTextDesc',
+ {
+ defaultMessage: 'High-Low',
+ description: 'Descending number label',
+ }
+ ),
+ 'euiDataGridSchema.jsonSortTextAsc': i18n.translate('core.euiDataGridSchema.jsonSortTextAsc', {
+ defaultMessage: 'Small-Large',
+ description: 'Ascending size label',
+ }),
+ 'euiDataGridSchema.jsonSortTextDesc': i18n.translate('core.euiDataGridSchema.jsonSortTextDesc', {
+ defaultMessage: 'Large-Small',
+ description: 'Descending size label',
+ }),
+ 'euiFilterButton.filterBadge': ({ count, hasActiveFilters }: EuiValues) =>
+ i18n.translate('core.euiFilterButton.filterBadge', {
+ defaultMessage: '${count} ${filterCountLabel} filters',
+ values: { count, filterCountLabel: hasActiveFilters ? 'active' : 'available' },
+ }),
+ 'euiForm.addressFormErrors': i18n.translate('core.euiForm.addressFormErrors', {
+ defaultMessage: 'Please address the errors in your form.',
+ }),
+ 'euiFormControlLayoutClearButton.label': i18n.translate(
+ 'core.euiFormControlLayoutClearButton.label',
+ {
+ defaultMessage: 'Clear input',
+ description: 'ARIA label on a button that removes any entry in a form field',
+ }
+ ),
+ 'euiHeaderAlert.dismiss': i18n.translate('core.euiHeaderAlert.dismiss', {
+ defaultMessage: 'Dismiss',
+ description: 'ARIA label on a button that dismisses/removes a notification',
+ }),
+ 'euiHeaderLinks.appNavigation': i18n.translate('core.euiHeaderLinks.appNavigation', {
+ defaultMessage: 'App navigation',
+ description: 'ARIA label on a `nav` element',
+ }),
+ 'euiHeaderLinks.openNavigationMenu': i18n.translate('core.euiHeaderLinks.openNavigationMenu', {
+ defaultMessage: 'Open navigation menu',
+ }),
+ 'euiHue.label': i18n.translate('core.euiHue.label', {
+ defaultMessage: 'Select the HSV color mode "hue" value',
+ }),
+ 'euiImage.closeImage': ({ alt }: EuiValues) =>
+ i18n.translate('core.euiImage.closeImage', {
+ defaultMessage: 'Close full screen {alt} image',
+ values: { alt },
+ }),
+ 'euiImage.openImage': ({ alt }: EuiValues) =>
+ i18n.translate('core.euiImage.openImage', {
+ defaultMessage: 'Open full screen {alt} image',
+ values: { alt },
+ }),
+ 'euiLink.external.ariaLabel': i18n.translate('core.euiLink.external.ariaLabel', {
+ defaultMessage: 'External link',
+ }),
+ 'euiModal.closeModal': i18n.translate('core.euiModal.closeModal', {
+ defaultMessage: 'Closes this modal window',
+ }),
+ 'euiPagination.jumpToLastPage': ({ pageCount }: EuiValues) =>
+ i18n.translate('core.euiPagination.jumpToLastPage', {
+ defaultMessage: 'Jump to the last page, number {pageCount}',
+ values: { pageCount },
+ }),
+ 'euiPagination.nextPage': i18n.translate('core.euiPagination.nextPage', {
+ defaultMessage: 'Next page',
+ }),
+ 'euiPagination.pageOfTotal': ({ page, total }: EuiValues) =>
+ i18n.translate('core.euiPagination.pageOfTotal', {
+ defaultMessage: 'Page {page} of {total}',
+ values: { page, total },
+ }),
+ 'euiPagination.previousPage': i18n.translate('core.euiPagination.previousPage', {
+ defaultMessage: 'Previous page',
+ }),
+ 'euiPopover.screenReaderAnnouncement': i18n.translate(
+ 'core.euiPopover.screenReaderAnnouncement',
+ {
+ defaultMessage: 'You are in a dialog. To close this dialog, hit escape.',
+ }
+ ),
+ 'euiQuickSelect.applyButton': i18n.translate('core.euiQuickSelect.applyButton', {
+ defaultMessage: 'Apply',
+ }),
+ 'euiQuickSelect.fullDescription': ({ timeTense, timeValue, timeUnit }: EuiValues) =>
+ i18n.translate('core.euiQuickSelect.fullDescription', {
+ defaultMessage: 'Currently set to {timeTense} {timeValue} {timeUnit}.',
+ values: { timeTense, timeValue, timeUnit },
+ }),
+ 'euiQuickSelect.legendText': i18n.translate('core.euiQuickSelect.legendText', {
+ defaultMessage: 'Quick select a time range',
+ }),
+ 'euiQuickSelect.nextLabel': i18n.translate('core.euiQuickSelect.nextLabel', {
+ defaultMessage: 'Next time window',
+ }),
+ 'euiQuickSelect.previousLabel': i18n.translate('core.euiQuickSelect.previousLabel', {
+ defaultMessage: 'Previous time window',
+ }),
+ 'euiQuickSelect.quickSelectTitle': i18n.translate('core.euiQuickSelect.quickSelectTitle', {
+ defaultMessage: 'Quick select',
+ }),
+ 'euiQuickSelect.tenseLabel': i18n.translate('core.euiQuickSelect.tenseLabel', {
+ defaultMessage: 'Time tense',
+ }),
+ 'euiQuickSelect.unitLabel': i18n.translate('core.euiQuickSelect.unitLabel', {
+ defaultMessage: 'Time unit',
+ }),
+ 'euiQuickSelect.valueLabel': i18n.translate('core.euiQuickSelect.valueLabel', {
+ defaultMessage: 'Time value',
+ }),
+ 'euiRefreshInterval.fullDescription': ({ optionValue, optionText }: EuiValues) =>
+ i18n.translate('core.euiRefreshInterval.fullDescription', {
+ defaultMessage: 'Currently set to {optionValue} {optionText}.',
+ values: { optionValue, optionText },
+ }),
+ 'euiRefreshInterval.legend': i18n.translate('core.euiRefreshInterval.legend', {
+ defaultMessage: 'Refresh every',
+ }),
+ 'euiRefreshInterval.start': i18n.translate('core.euiRefreshInterval.start', {
+ defaultMessage: 'Start',
+ }),
+ 'euiRefreshInterval.stop': i18n.translate('core.euiRefreshInterval.stop', {
+ defaultMessage: 'Stop',
+ }),
+ 'euiRelativeTab.fullDescription': ({ unit }: EuiValues) =>
+ i18n.translate('core.euiRelativeTab.fullDescription', {
+ defaultMessage: 'The unit is changeable. Currently set to {unit}.',
+ values: { unit },
+ }),
+ 'euiRelativeTab.relativeDate': ({ position }: EuiValues) =>
+ i18n.translate('core.euiRelativeTab.relativeDate', {
+ defaultMessage: '{position} date',
+ values: { position },
+ }),
+ 'euiRelativeTab.roundingLabel': ({ unit }: EuiValues) =>
+ i18n.translate('core.euiRelativeTab.roundingLabel', {
+ defaultMessage: 'Round to the {unit}',
+ values: { unit },
+ }),
+ 'euiRelativeTab.unitInputLabel': i18n.translate('core.euiRelativeTab.unitInputLabel', {
+ defaultMessage: 'Relative time span',
+ }),
+ 'euiSaturation.roleDescription': i18n.translate('core.euiSaturation.roleDescription', {
+ defaultMessage: 'HSV color mode saturation and value selection',
+ }),
+ 'euiSaturation.screenReaderAnnouncement': i18n.translate(
+ 'core.euiSaturation.screenReaderAnnouncement',
+ {
+ defaultMessage:
+ 'Use the arrow keys to navigate the square color gradient. The coordinates resulting from each key press will be used to calculate HSV color mode "saturation" and "value" numbers, in the range of 0 to 1. Left and right decrease and increase (respectively) the "saturation" value. Up and down decrease and increase (respectively) the "value" value.',
+ }
+ ),
+ 'euiSelectable.loadingOptions': i18n.translate('core.euiSelectable.loadingOptions', {
+ defaultMessage: 'Loading options',
+ description: 'Placeholder message while data is asynchronously loaded',
+ }),
+ 'euiSelectable.noAvailableOptions': i18n.translate('core.euiSelectable.noAvailableOptions', {
+ defaultMessage: "There aren't any options available",
+ }),
+ 'euiSelectable.noMatchingOptions': ({ searchValue }: EuiValues) => (
+
+ ),
+ 'euiStat.loadingText': i18n.translate('core.euiStat.loadingText', {
+ defaultMessage: 'Statistic is loading',
+ }),
+ 'euiStep.ariaLabel': ({ status }: EuiValues) =>
+ i18n.translate('core.euiStep.ariaLabel', {
+ defaultMessage: '{stepStatus}',
+ values: { stepStatus: status === 'incomplete' ? 'Incomplete Step' : 'Step' },
+ }),
+ 'euiStepHorizontal.buttonTitle': ({ step, title, disabled, isComplete }: EuiValues) => {
+ return i18n.translate('core.euiStepHorizontal.buttonTitle', {
+ defaultMessage: 'Step {step}: {title}{titleAppendix}',
+ values: {
+ step,
+ title,
+ titleAppendix: disabled ? ' is disabled' : isComplete ? ' is complete' : '',
+ },
+ });
+ },
+ 'euiStepHorizontal.step': i18n.translate('core.euiStepHorizontal.step', {
+ defaultMessage: 'Step',
+ description: 'Screen reader text announcing information about a step in some process',
+ }),
+ 'euiStepNumber.hasErrors': i18n.translate('core.euiStepNumber.hasErrors', {
+ defaultMessage: 'has errors',
+ description:
+ 'Used as the title attribute on an image or svg icon to indicate a given process step has errors',
+ }),
+ 'euiStepNumber.hasWarnings': i18n.translate('core.euiStepNumber.hasWarnings', {
+ defaultMessage: 'has warnings',
+ description:
+ 'Used as the title attribute on an image or svg icon to indicate a given process step has warnings',
+ }),
+ 'euiStepNumber.isComplete': i18n.translate('core.euiStepNumber.isComplete', {
+ defaultMessage: 'complete',
+ description:
+ 'Used as the title attribute on an image or svg icon to indicate a given process step is complete',
+ }),
+ 'euiStyleSelector.buttonText': i18n.translate('core.euiStyleSelector.buttonText', {
+ defaultMessage: 'Density',
+ }),
+ 'euiSuperDatePicker.showDatesButtonLabel': i18n.translate(
+ 'core.euiSuperDatePicker.showDatesButtonLabel',
+ {
+ defaultMessage: 'Show dates',
+ description: 'Displayed in a button that shows date picker',
+ }
+ ),
+ 'euiSuperSelect.screenReaderAnnouncement': ({ optionsCount }: EuiValues) =>
+ i18n.translate('core.euiSuperSelect.screenReaderAnnouncement', {
+ defaultMessage:
+ 'You are in a form selector of {optionsCount} items and must select a single option. Use the Up and Down keys to navigate or Escape to close.',
+ values: { optionsCount },
+ }),
+ 'euiSuperSelectControl.selectAnOption': ({ selectedValue }: EuiValues) =>
+ i18n.translate('core.euiSuperSelectControl.selectAnOption', {
+ defaultMessage: 'Select an option: {selectedValue}, is selected',
+ values: { selectedValue },
+ }),
+ 'euiSuperUpdateButton.cannotUpdateTooltip': i18n.translate(
+ 'core.euiSuperUpdateButton.cannotUpdateTooltip',
+ {
+ defaultMessage: 'Cannot update',
+ description: "Displayed in a tooltip when updates can't happen",
+ }
+ ),
+ 'euiSuperUpdateButton.clickToApplyTooltip': i18n.translate(
+ 'core.euiSuperUpdateButton.clickToApplyTooltip',
+ {
+ defaultMessage: 'Click to apply',
+ description: "Displayed in a tooltip when there are changes that haven't been applied",
+ }
+ ),
+ 'euiSuperUpdateButton.refreshButtonLabel': i18n.translate(
+ 'core.euiSuperUpdateButton.refreshButtonLabel',
+ {
+ defaultMessage: 'Refresh',
+ description: 'Displayed in a button that refreshes based on date picked',
+ }
+ ),
+ 'euiSuperUpdateButton.updatingButtonLabel': i18n.translate(
+ 'core.euiSuperUpdateButton.updatingButtonLabel',
+ {
+ defaultMessage: 'Updating',
+ description: 'Displayed in a button that refreshes when updates are happening',
+ }
+ ),
+ 'euiSuperUpdateButton.updateButtonLabel': i18n.translate(
+ 'core.euiSuperUpdateButton.updateButtonLabel',
+ {
+ defaultMessage: 'Update',
+ description: 'Displayed in a button that updates based on date picked',
+ }
+ ),
+ 'euiTablePagination.rowsPerPage': i18n.translate('core.euiTablePagination.rowsPerPage', {
+ defaultMessage: 'Rows per page',
+ description: 'Displayed in a button that toggles a table pagination menu',
+ }),
+ 'euiTablePagination.rowsPerPageOption': ({ rowsPerPage }: EuiValues) =>
+ i18n.translate('core.euiTablePagination.rowsPerPageOption', {
+ defaultMessage: '{rowsPerPage} rows',
+ description: 'Displayed in a button that toggles the number of visible rows',
+ values: { rowsPerPage },
+ }),
+ 'euiTableSortMobile.sorting': i18n.translate('core.euiTableSortMobile.sorting', {
+ defaultMessage: 'Sorting',
+ description: 'Displayed in a button that toggles a table sorting menu',
+ }),
+ 'euiToast.dismissToast': i18n.translate('core.euiToast.dismissToast', {
+ defaultMessage: 'Dismiss toast',
+ }),
+ 'euiToast.newNotification': i18n.translate('core.euiToast.newNotification', {
+ defaultMessage: 'A new notification appears',
+ }),
+ 'euiToast.notification': i18n.translate('core.euiToast.notification', {
+ defaultMessage: 'Notification',
+ description: 'ARIA label on an element containing a notification',
+ }),
+ 'euiTreeView.ariaLabel': ({ nodeLabel, ariaLabel }: EuiValues) =>
+ i18n.translate('core.euiTreeView.ariaLabel', {
+ defaultMessage: '{nodeLabel} child of {ariaLabel}',
+ values: { nodeLabel, ariaLabel },
+ }),
+ 'euiTreeView.listNavigationInstructions': i18n.translate(
+ 'core.euiTreeView.listNavigationInstructions',
+ {
+ defaultMessage: 'You can quickly navigate this list using arrow keys.',
+ }
+ ),
+};
diff --git a/src/core/public/i18n/i18n_service.tsx b/src/core/public/i18n/i18n_service.tsx
index 721c5d49634f4..501d83e36b1b9 100644
--- a/src/core/public/i18n/i18n_service.tsx
+++ b/src/core/public/i18n/i18n_service.tsx
@@ -18,14 +18,10 @@
*/
import React from 'react';
-
import { EuiContext } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
+import { I18nProvider } from '@kbn/i18n/react';
-interface EuiValues {
- [key: string]: any;
-}
+import { euiContextMapping } from './i18n_eui_mapping';
/**
* Service that is responsible for i18n capabilities.
@@ -42,575 +38,8 @@ export class I18nService {
*/
public getContext(): I18nStart {
const mapping = {
- 'euiBasicTable.selectAllRows': i18n.translate('core.euiBasicTable.selectAllRows', {
- defaultMessage: 'Select all rows',
- description: 'ARIA and displayed label on a checkbox to select all table rows',
- }),
- 'euiBasicTable.selectThisRow': i18n.translate('core.euiBasicTable.selectThisRow', {
- defaultMessage: 'Select this row',
- description: 'ARIA and displayed label on a checkbox to select a single table row',
- }),
- 'euiBasicTable.tableDescription': ({ itemCount }: EuiValues) =>
- i18n.translate('core.euiBasicTable.tableDescription', {
- defaultMessage: 'Below is a table of {itemCount} items.',
- values: { itemCount },
- description: 'Screen reader text to describe the size of a table',
- }),
- 'euiBottomBar.screenReaderAnnouncement': i18n.translate(
- 'core.euiBottomBar.screenReaderAnnouncement',
- {
- defaultMessage:
- 'There is a new menu opening with page level controls at the end of the document.',
- description:
- 'Screen reader announcement that functionality is available in the page document',
- }
- ),
- 'euiBreadcrumbs.collapsedBadge.ariaLabel': i18n.translate(
- 'core.euiBreadcrumbs.collapsedBadge.ariaLabel',
- {
- defaultMessage: 'Show all breadcrumbs',
- description: 'Displayed when one or more breadcrumbs are hidden.',
- }
- ),
- 'euiCardSelect.select': i18n.translate('core.euiCardSelect.select', {
- defaultMessage: 'Select',
- description: 'Displayed button text when a card option can be selected.',
- }),
- 'euiCardSelect.selected': i18n.translate('core.euiCardSelect.selected', {
- defaultMessage: 'Selected',
- description: 'Displayed button text when a card option is selected.',
- }),
- 'euiCardSelect.unavailable': i18n.translate('core.euiCardSelect.unavailable', {
- defaultMessage: 'Unavailable',
- description: 'Displayed button text when a card option is unavailable.',
- }),
- 'euiCodeBlock.copyButton': i18n.translate('core.euiCodeBlock.copyButton', {
- defaultMessage: 'Copy',
- description: 'ARIA label for a button that copies source code text to the clipboard',
- }),
- 'euiCodeEditor.startEditing': i18n.translate('core.euiCodeEditor.startEditing', {
- defaultMessage: 'Press Enter to start editing.',
- }),
- 'euiCodeEditor.startInteracting': i18n.translate('core.euiCodeEditor.startInteracting', {
- defaultMessage: 'Press Enter to start interacting with the code.',
- }),
- 'euiCodeEditor.stopEditing': i18n.translate('core.euiCodeEditor.stopEditing', {
- defaultMessage: "When you're done, press Escape to stop editing.",
- }),
- 'euiCodeEditor.stopInteracting': i18n.translate('core.euiCodeEditor.stopInteracting', {
- defaultMessage: "When you're done, press Escape to stop interacting with the code.",
- }),
- 'euiCollapsedItemActions.allActions': i18n.translate(
- 'core.euiCollapsedItemActions.allActions',
- {
- defaultMessage: 'All actions',
- description:
- 'ARIA label and tooltip content describing a button that expands an actions menu',
- }
- ),
- 'euiColorPicker.screenReaderAnnouncement': i18n.translate(
- 'core.euiColorPicker.screenReaderAnnouncement',
- {
- defaultMessage:
- 'A popup with a range of selectable colors opened. Tab forward to cycle through colors choices or press escape to close this popup.',
- description:
- 'Message when the color picker popover is opened. Describes the interaction with the elements in the popover.',
- }
- ),
- 'euiColorPicker.swatchAriaLabel': ({ swatch }: EuiValues) =>
- i18n.translate('core.euiColorPicker.swatchAriaLabel', {
- defaultMessage: 'Select {swatch} as the color',
- values: { swatch },
- description:
- 'Screen reader text to describe the action and hex value of the selectable option',
- }),
- 'euiColorStopThumb.removeLabel': i18n.translate('core.euiColorStopThumb.removeLabel', {
- defaultMessage: 'Remove this stop',
- description: 'Label accompanying a button whose action will remove the color stop',
- }),
- 'euiColorStopThumb.screenReaderAnnouncement': i18n.translate(
- 'core.euiColorStopThumb.screenReaderAnnouncement',
- {
- defaultMessage:
- 'A popup with a color stop edit form opened. Tab forward to cycle through form controls or press escape to close this popup.',
- description:
- 'Message when the color picker popover has opened for an individual color stop thumb.',
- }
- ),
- 'euiColorStops.screenReaderAnnouncement': ({ label, readOnly, disabled }: EuiValues) =>
- i18n.translate('core.euiColorStops.screenReaderAnnouncement', {
- defaultMessage:
- '{label}: {readOnly} {disabled} Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop.',
- values: { label, readOnly, disabled },
- description:
- 'Screen reader text to describe the composite behavior of the color stops component.',
- }),
- 'euiColumnSelector.hideAll': i18n.translate('core.euiColumnSelector.hideAll', {
- defaultMessage: 'Hide all',
- }),
- 'euiColumnSelector.selectAll': i18n.translate('core.euiColumnSelector.selectAll', {
- defaultMessage: 'Show all',
- }),
- 'euiColumnSorting.clearAll': i18n.translate('core.euiColumnSorting.clearAll', {
- defaultMessage: 'Clear sorting',
- }),
- 'euiColumnSorting.emptySorting': i18n.translate('core.euiColumnSorting.emptySorting', {
- defaultMessage: 'Currently no fields are sorted',
- }),
- 'euiColumnSorting.pickFields': i18n.translate('core.euiColumnSorting.pickFields', {
- defaultMessage: 'Pick fields to sort by',
- }),
- 'euiColumnSorting.sortFieldAriaLabel': i18n.translate(
- 'core.euiColumnSorting.sortFieldAriaLabel',
- {
- defaultMessage: 'Sort by:',
- }
- ),
- 'euiColumnSortingDraggable.activeSortLabel': i18n.translate(
- 'core.euiColumnSortingDraggable.activeSortLabel',
- {
- defaultMessage: 'is sorting this data grid',
- }
- ),
- 'euiColumnSortingDraggable.defaultSortAsc': i18n.translate(
- 'core.euiColumnSortingDraggable.defaultSortAsc',
- {
- defaultMessage: 'A-Z',
- description: 'Ascending sort label',
- }
- ),
- 'euiColumnSortingDraggable.defaultSortDesc': i18n.translate(
- 'core.euiColumnSortingDraggable.defaultSortDesc',
- {
- defaultMessage: 'Z-A',
- description: 'Descending sort label',
- }
- ),
- 'euiColumnSortingDraggable.removeSortLabel': i18n.translate(
- 'core.euiColumnSortingDraggable.removeSortLabel',
- {
- defaultMessage: 'Remove from data grid sort:',
- }
- ),
- 'euiColumnSortingDraggable.toggleLegend': i18n.translate(
- 'core.euiColumnSortingDraggable.toggleLegend',
- {
- defaultMessage: 'Select sorting method for field:',
- }
- ),
- 'euiComboBoxOptionsList.allOptionsSelected': i18n.translate(
- 'core.euiComboBoxOptionsList.allOptionsSelected',
- {
- defaultMessage: "You've selected all available options",
- }
- ),
- 'euiComboBoxOptionsList.alreadyAdded': ({ label }: EuiValues) => (
-
- ),
- 'euiComboBoxOptionsList.createCustomOption': ({ key, searchValue }: EuiValues) => (
-
- ),
- 'euiComboBoxOptionsList.loadingOptions': i18n.translate(
- 'core.euiComboBoxOptionsList.loadingOptions',
- {
- defaultMessage: 'Loading options',
- description: 'Placeholder message while data is asynchronously loaded',
- }
- ),
- 'euiComboBoxOptionsList.noAvailableOptions': i18n.translate(
- 'core.euiComboBoxOptionsList.noAvailableOptions',
- {
- defaultMessage: "There aren't any options available",
- }
- ),
- 'euiComboBoxOptionsList.noMatchingOptions': ({ searchValue }: EuiValues) => (
-
- ),
- 'euiComboBoxPill.removeSelection': ({ children }: EuiValues) =>
- i18n.translate('core.euiComboBoxPill.removeSelection', {
- defaultMessage: 'Remove {children} from selection in this group',
- values: { children },
- description: 'ARIA label, `children` is the human-friendly value of an option',
- }),
- 'euiCommonlyUsedTimeRanges.legend': i18n.translate('core.euiCommonlyUsedTimeRanges.legend', {
- defaultMessage: 'Commonly used',
- }),
- 'euiDataGrid.screenReaderNotice': i18n.translate('core.euiDataGrid.screenReaderNotice', {
- defaultMessage: 'Cell contains interactive content.',
- }),
- 'euiDataGridCell.expandButtonTitle': i18n.translate(
- 'core.euiDataGridCell.expandButtonTitle',
- {
- defaultMessage: 'Click or hit enter to interact with cell content',
- }
- ),
- 'euiDataGridSchema.booleanSortTextAsc': i18n.translate(
- 'core.euiDataGridSchema.booleanSortTextAsc',
- {
- defaultMessage: 'True-False',
- description: 'Ascending boolean label',
- }
- ),
- 'euiDataGridSchema.booleanSortTextDesc': i18n.translate(
- 'core.euiDataGridSchema.booleanSortTextDesc',
- {
- defaultMessage: 'False-True',
- description: 'Descending boolean label',
- }
- ),
- 'euiDataGridSchema.currencySortTextAsc': i18n.translate(
- 'core.euiDataGridSchema.currencySortTextAsc',
- {
- defaultMessage: 'Low-High',
- description: 'Ascending currency label',
- }
- ),
- 'euiDataGridSchema.currencySortTextDesc': i18n.translate(
- 'core.euiDataGridSchema.currencySortTextDesc',
- {
- defaultMessage: 'High-Low',
- description: 'Descending currency label',
- }
- ),
- 'euiDataGridSchema.dateSortTextAsc': i18n.translate(
- 'core.euiDataGridSchema.dateSortTextAsc',
- {
- defaultMessage: 'New-Old',
- description: 'Ascending date label',
- }
- ),
- 'euiDataGridSchema.dateSortTextDesc': i18n.translate(
- 'core.euiDataGridSchema.dateSortTextDesc',
- {
- defaultMessage: 'Old-New',
- description: 'Descending date label',
- }
- ),
- 'euiDataGridSchema.numberSortTextAsc': i18n.translate(
- 'core.euiDataGridSchema.numberSortTextAsc',
- {
- defaultMessage: 'Low-High',
- description: 'Ascending number label',
- }
- ),
- 'euiDataGridSchema.numberSortTextDesc': i18n.translate(
- 'core.euiDataGridSchema.numberSortTextDesc',
- {
- defaultMessage: 'High-Low',
- description: 'Descending number label',
- }
- ),
- 'euiDataGridSchema.jsonSortTextAsc': i18n.translate(
- 'core.euiDataGridSchema.jsonSortTextAsc',
- {
- defaultMessage: 'Small-Large',
- description: 'Ascending size label',
- }
- ),
- 'euiDataGridSchema.jsonSortTextDesc': i18n.translate(
- 'core.euiDataGridSchema.jsonSortTextDesc',
- {
- defaultMessage: 'Large-Small',
- description: 'Descending size label',
- }
- ),
- 'euiFilterButton.filterBadge': ({ count, hasActiveFilters }: EuiValues) =>
- i18n.translate('core.euiFilterButton.filterBadge', {
- defaultMessage: '${count} ${filterCountLabel} filters',
- values: { count, filterCountLabel: hasActiveFilters ? 'active' : 'available' },
- }),
- 'euiForm.addressFormErrors': i18n.translate('core.euiForm.addressFormErrors', {
- defaultMessage: 'Please address the errors in your form.',
- }),
- 'euiFormControlLayoutClearButton.label': i18n.translate(
- 'core.euiFormControlLayoutClearButton.label',
- {
- defaultMessage: 'Clear input',
- description: 'ARIA label on a button that removes any entry in a form field',
- }
- ),
- 'euiHeaderAlert.dismiss': i18n.translate('core.euiHeaderAlert.dismiss', {
- defaultMessage: 'Dismiss',
- description: 'ARIA label on a button that dismisses/removes a notification',
- }),
- 'euiHeaderLinks.appNavigation': i18n.translate('core.euiHeaderLinks.appNavigation', {
- defaultMessage: 'App navigation',
- description: 'ARIA label on a `nav` element',
- }),
- 'euiHeaderLinks.openNavigationMenu': i18n.translate(
- 'core.euiHeaderLinks.openNavigationMenu',
- {
- defaultMessage: 'Open navigation menu',
- }
- ),
- 'euiHue.label': i18n.translate('core.euiHue.label', {
- defaultMessage: 'Select the HSV color mode "hue" value',
- }),
- 'euiImage.closeImage': ({ alt }: EuiValues) =>
- i18n.translate('core.euiImage.closeImage', {
- defaultMessage: 'Close full screen {alt} image',
- values: { alt },
- }),
- 'euiImage.openImage': ({ alt }: EuiValues) =>
- i18n.translate('core.euiImage.openImage', {
- defaultMessage: 'Open full screen {alt} image',
- values: { alt },
- }),
- 'euiLink.external.ariaLabel': i18n.translate('core.euiLink.external.ariaLabel', {
- defaultMessage: 'External link',
- }),
- 'euiModal.closeModal': i18n.translate('core.euiModal.closeModal', {
- defaultMessage: 'Closes this modal window',
- }),
- 'euiPagination.jumpToLastPage': ({ pageCount }: EuiValues) =>
- i18n.translate('core.euiPagination.jumpToLastPage', {
- defaultMessage: 'Jump to the last page, number {pageCount}',
- values: { pageCount },
- }),
- 'euiPagination.nextPage': i18n.translate('core.euiPagination.nextPage', {
- defaultMessage: 'Next page',
- }),
- 'euiPagination.pageOfTotal': ({ page, total }: EuiValues) =>
- i18n.translate('core.euiPagination.pageOfTotal', {
- defaultMessage: 'Page {page} of {total}',
- values: { page, total },
- }),
- 'euiPagination.previousPage': i18n.translate('core.euiPagination.previousPage', {
- defaultMessage: 'Previous page',
- }),
- 'euiPopover.screenReaderAnnouncement': i18n.translate(
- 'core.euiPopover.screenReaderAnnouncement',
- {
- defaultMessage: 'You are in a dialog. To close this dialog, hit escape.',
- }
- ),
- 'euiQuickSelect.applyButton': i18n.translate('core.euiQuickSelect.applyButton', {
- defaultMessage: 'Apply',
- }),
- 'euiQuickSelect.fullDescription': ({ timeTense, timeValue, timeUnit }: EuiValues) =>
- i18n.translate('core.euiQuickSelect.fullDescription', {
- defaultMessage: 'Currently set to {timeTense} {timeValue} {timeUnit}.',
- values: { timeTense, timeValue, timeUnit },
- }),
- 'euiQuickSelect.legendText': i18n.translate('core.euiQuickSelect.legendText', {
- defaultMessage: 'Quick select a time range',
- }),
- 'euiQuickSelect.nextLabel': i18n.translate('core.euiQuickSelect.nextLabel', {
- defaultMessage: 'Next time window',
- }),
- 'euiQuickSelect.previousLabel': i18n.translate('core.euiQuickSelect.previousLabel', {
- defaultMessage: 'Previous time window',
- }),
- 'euiQuickSelect.quickSelectTitle': i18n.translate('core.euiQuickSelect.quickSelectTitle', {
- defaultMessage: 'Quick select',
- }),
- 'euiQuickSelect.tenseLabel': i18n.translate('core.euiQuickSelect.tenseLabel', {
- defaultMessage: 'Time tense',
- }),
- 'euiQuickSelect.unitLabel': i18n.translate('core.euiQuickSelect.unitLabel', {
- defaultMessage: 'Time unit',
- }),
- 'euiQuickSelect.valueLabel': i18n.translate('core.euiQuickSelect.valueLabel', {
- defaultMessage: 'Time value',
- }),
- 'euiRefreshInterval.fullDescription': ({ optionValue, optionText }: EuiValues) =>
- i18n.translate('core.euiRefreshInterval.fullDescription', {
- defaultMessage: 'Currently set to {optionValue} {optionText}.',
- values: { optionValue, optionText },
- }),
- 'euiRefreshInterval.legend': i18n.translate('core.euiRefreshInterval.legend', {
- defaultMessage: 'Refresh every',
- }),
- 'euiRefreshInterval.start': i18n.translate('core.euiRefreshInterval.start', {
- defaultMessage: 'Start',
- }),
- 'euiRefreshInterval.stop': i18n.translate('core.euiRefreshInterval.stop', {
- defaultMessage: 'Stop',
- }),
- 'euiRelativeTab.fullDescription': ({ unit }: EuiValues) =>
- i18n.translate('core.euiRelativeTab.fullDescription', {
- defaultMessage: 'The unit is changeable. Currently set to {unit}.',
- values: { unit },
- }),
- 'euiRelativeTab.relativeDate': ({ position }: EuiValues) =>
- i18n.translate('core.euiRelativeTab.relativeDate', {
- defaultMessage: '{position} date',
- values: { position },
- }),
- 'euiRelativeTab.roundingLabel': ({ unit }: EuiValues) =>
- i18n.translate('core.euiRelativeTab.roundingLabel', {
- defaultMessage: 'Round to the {unit}',
- values: { unit },
- }),
- 'euiRelativeTab.unitInputLabel': i18n.translate('core.euiRelativeTab.unitInputLabel', {
- defaultMessage: 'Relative time span',
- }),
- 'euiSaturation.roleDescription': i18n.translate('core.euiSaturation.roleDescription', {
- defaultMessage: 'HSV color mode saturation and value selection',
- }),
- 'euiSaturation.screenReaderAnnouncement': i18n.translate(
- 'core.euiSaturation.screenReaderAnnouncement',
- {
- defaultMessage:
- 'Use the arrow keys to navigate the square color gradient. The coordinates resulting from each key press will be used to calculate HSV color mode "saturation" and "value" numbers, in the range of 0 to 1. Left and right decrease and increase (respectively) the "saturation" value. Up and down decrease and increase (respectively) the "value" value.',
- }
- ),
- 'euiSelectable.loadingOptions': i18n.translate('core.euiSelectable.loadingOptions', {
- defaultMessage: 'Loading options',
- description: 'Placeholder message while data is asynchronously loaded',
- }),
- 'euiSelectable.noAvailableOptions': i18n.translate('core.euiSelectable.noAvailableOptions', {
- defaultMessage: "There aren't any options available",
- }),
- 'euiSelectable.noMatchingOptions': ({ searchValue }: EuiValues) => (
-
- ),
- 'euiStat.loadingText': i18n.translate('core.euiStat.loadingText', {
- defaultMessage: 'Statistic is loading',
- }),
- 'euiStep.ariaLabel': ({ status }: EuiValues) =>
- i18n.translate('core.euiStep.ariaLabel', {
- defaultMessage: '{stepStatus}',
- values: { stepStatus: status === 'incomplete' ? 'Incomplete Step' : 'Step' },
- }),
- 'euiStepHorizontal.buttonTitle': ({ step, title, disabled, isComplete }: EuiValues) => {
- return i18n.translate('core.euiStepHorizontal.buttonTitle', {
- defaultMessage: 'Step {step}: {title}{titleAppendix}',
- values: {
- step,
- title,
- titleAppendix: disabled ? ' is disabled' : isComplete ? ' is complete' : '',
- },
- });
- },
- 'euiStepHorizontal.step': i18n.translate('core.euiStepHorizontal.step', {
- defaultMessage: 'Step',
- description: 'Screen reader text announcing information about a step in some process',
- }),
- 'euiStepNumber.hasErrors': i18n.translate('core.euiStepNumber.hasErrors', {
- defaultMessage: 'has errors',
- description:
- 'Used as the title attribute on an image or svg icon to indicate a given process step has errors',
- }),
- 'euiStepNumber.hasWarnings': i18n.translate('core.euiStepNumber.hasWarnings', {
- defaultMessage: 'has warnings',
- description:
- 'Used as the title attribute on an image or svg icon to indicate a given process step has warnings',
- }),
- 'euiStepNumber.isComplete': i18n.translate('core.euiStepNumber.isComplete', {
- defaultMessage: 'complete',
- description:
- 'Used as the title attribute on an image or svg icon to indicate a given process step is complete',
- }),
- 'euiStyleSelector.buttonText': i18n.translate('core.euiStyleSelector.buttonText', {
- defaultMessage: 'Density',
- }),
- 'euiSuperDatePicker.showDatesButtonLabel': i18n.translate(
- 'core.euiSuperDatePicker.showDatesButtonLabel',
- {
- defaultMessage: 'Show dates',
- description: 'Displayed in a button that shows date picker',
- }
- ),
- 'euiSuperSelect.screenReaderAnnouncement': ({ optionsCount }: EuiValues) =>
- i18n.translate('core.euiSuperSelect.screenReaderAnnouncement', {
- defaultMessage:
- 'You are in a form selector of {optionsCount} items and must select a single option. Use the Up and Down keys to navigate or Escape to close.',
- values: { optionsCount },
- }),
- 'euiSuperSelectControl.selectAnOption': ({ selectedValue }: EuiValues) =>
- i18n.translate('core.euiSuperSelectControl.selectAnOption', {
- defaultMessage: 'Select an option: {selectedValue}, is selected',
- values: { selectedValue },
- }),
- 'euiSuperUpdateButton.cannotUpdateTooltip': i18n.translate(
- 'core.euiSuperUpdateButton.cannotUpdateTooltip',
- {
- defaultMessage: 'Cannot update',
- description: "Displayed in a tooltip when updates can't happen",
- }
- ),
- 'euiSuperUpdateButton.clickToApplyTooltip': i18n.translate(
- 'core.euiSuperUpdateButton.clickToApplyTooltip',
- {
- defaultMessage: 'Click to apply',
- description: "Displayed in a tooltip when there are changes that haven't been applied",
- }
- ),
- 'euiSuperUpdateButton.refreshButtonLabel': i18n.translate(
- 'core.euiSuperUpdateButton.refreshButtonLabel',
- {
- defaultMessage: 'Refresh',
- description: 'Displayed in a button that refreshes based on date picked',
- }
- ),
- 'euiSuperUpdateButton.updatingButtonLabel': i18n.translate(
- 'core.euiSuperUpdateButton.updatingButtonLabel',
- {
- defaultMessage: 'Updating',
- description: 'Displayed in a button that refreshes when updates are happening',
- }
- ),
- 'euiSuperUpdateButton.updateButtonLabel': i18n.translate(
- 'core.euiSuperUpdateButton.updateButtonLabel',
- {
- defaultMessage: 'Update',
- description: 'Displayed in a button that updates based on date picked',
- }
- ),
- 'euiTablePagination.rowsPerPage': i18n.translate('core.euiTablePagination.rowsPerPage', {
- defaultMessage: 'Rows per page',
- description: 'Displayed in a button that toggles a table pagination menu',
- }),
- 'euiTablePagination.rowsPerPageOption': ({ rowsPerPage }: EuiValues) =>
- i18n.translate('core.euiTablePagination.rowsPerPageOption', {
- defaultMessage: '{rowsPerPage} rows',
- description: 'Displayed in a button that toggles the number of visible rows',
- values: { rowsPerPage },
- }),
- 'euiTableSortMobile.sorting': i18n.translate('core.euiTableSortMobile.sorting', {
- defaultMessage: 'Sorting',
- description: 'Displayed in a button that toggles a table sorting menu',
- }),
- 'euiToast.dismissToast': i18n.translate('core.euiToast.dismissToast', {
- defaultMessage: 'Dismiss toast',
- }),
- 'euiToast.newNotification': i18n.translate('core.euiToast.newNotification', {
- defaultMessage: 'A new notification appears',
- }),
- 'euiToast.notification': i18n.translate('core.euiToast.notification', {
- defaultMessage: 'Notification',
- description: 'ARIA label on an element containing a notification',
- }),
- 'euiTreeView.ariaLabel': ({ nodeLabel, ariaLabel }: EuiValues) =>
- i18n.translate('core.euiTreeView.ariaLabel', {
- defaultMessage: '{nodeLabel} child of {ariaLabel}',
- values: { nodeLabel, ariaLabel },
- }),
- 'euiTreeView.listNavigationInstructions': i18n.translate(
- 'core.euiTreeView.listNavigationInstructions',
- {
- defaultMessage: 'You can quickly navigate this list using arrow keys.',
- }
- ),
+ ...euiContextMapping,
};
-
return {
Context: function I18nContext({ children }) {
return (
diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts
index 695f0454f8b65..644df259b8e24 100644
--- a/src/core/public/mocks.ts
+++ b/src/core/public/mocks.ts
@@ -18,7 +18,7 @@
*/
import { applicationServiceMock } from './application/application_service.mock';
import { chromeServiceMock } from './chrome/chrome_service.mock';
-import { CoreContext, CoreSetup, CoreStart, PluginInitializerContext, NotificationsSetup } from '.';
+import { CoreContext, PluginInitializerContext } from '.';
import { docLinksServiceMock } from './doc_links/doc_links_service.mock';
import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock';
import { httpServiceMock } from './http/http_service.mock';
@@ -42,7 +42,7 @@ export { overlayServiceMock } from './overlays/overlay_service.mock';
export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock';
function createCoreSetupMock({ basePath = '' } = {}) {
- const mock: MockedKeys & { notifications: MockedKeys } = {
+ const mock = {
application: applicationServiceMock.createSetupContract(),
context: contextServiceMock.createSetupContract(),
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
@@ -58,7 +58,7 @@ function createCoreSetupMock({ basePath = '' } = {}) {
}
function createCoreStartMock({ basePath = '' } = {}) {
- const mock: MockedKeys & { notifications: MockedKeys } = {
+ const mock = {
application: applicationServiceMock.createStartContract(),
chrome: chromeServiceMock.createStartContract(),
docLinks: docLinksServiceMock.createStartContract(),
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index 2dbf4d54efef6..6fbc7324ce393 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -63,6 +63,7 @@ export interface AppMountContext {
i18n: I18nStart;
notifications: NotificationsStart;
overlays: OverlayStart;
+ savedObjects: SavedObjectsStart;
uiSettings: IUiSettingsClient;
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts
index a78de8dfe17e4..a0cf3d1602879 100644
--- a/src/core/server/bootstrap.ts
+++ b/src/core/server/bootstrap.ts
@@ -71,7 +71,20 @@ export async function bootstrap({
const root = new Root(rawConfigService.getConfig$(), env, onRootShutdown);
- process.on('SIGHUP', () => {
+ process.on('SIGHUP', () => reloadLoggingConfig());
+
+ // This is only used by the LogRotator service
+ // in order to be able to reload the log configuration
+ // under the cluster mode
+ process.on('message', msg => {
+ if (!msg || msg.reloadLoggingConfig !== true) {
+ return;
+ }
+
+ reloadLoggingConfig();
+ });
+
+ function reloadLoggingConfig() {
const cliLogger = root.logger.get('cli');
cliLogger.info('Reloading logging configuration due to SIGHUP.', { tags: ['config'] });
@@ -82,7 +95,7 @@ export async function bootstrap({
}
cliLogger.info('Reloaded logging configuration due to SIGHUP.', { tags: ['config'] });
- });
+ }
process.on('SIGINT', () => shutdown());
process.on('SIGTERM', () => shutdown());
diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts
index f77184fb79ab6..244b3cca60f31 100644
--- a/src/core/server/http/http_server.ts
+++ b/src/core/server/http/http_server.ts
@@ -16,8 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-
-import { Request, Server } from 'hapi';
+import { Server } from 'hapi';
import url from 'url';
import { Logger, LoggerFactory } from '../logging';
@@ -26,8 +25,9 @@ import { createServer, getListenerOptions, getServerOptions } from './http_tools
import { adoptToHapiAuthFormat, AuthenticationHandler } from './lifecycle/auth';
import { adoptToHapiOnPostAuthFormat, OnPostAuthHandler } from './lifecycle/on_post_auth';
import { adoptToHapiOnPreAuthFormat, OnPreAuthHandler } from './lifecycle/on_pre_auth';
+import { adoptToHapiOnPreResponseFormat, OnPreResponseHandler } from './lifecycle/on_pre_response';
-import { ResponseHeaders, IRouter } from './router';
+import { IRouter } from './router';
import {
SessionStorageCookieOptions,
createCookieSessionStorageFactory,
@@ -50,6 +50,7 @@ export interface HttpServerSetup {
registerAuth: HttpServiceSetup['registerAuth'];
registerOnPreAuth: HttpServiceSetup['registerOnPreAuth'];
registerOnPostAuth: HttpServiceSetup['registerOnPostAuth'];
+ registerOnPreResponse: HttpServiceSetup['registerOnPreResponse'];
isTlsEnabled: HttpServiceSetup['isTlsEnabled'];
auth: {
get: GetAuthState;
@@ -103,6 +104,7 @@ export class HttpServer {
registerRouter: this.registerRouter.bind(this),
registerOnPreAuth: this.registerOnPreAuth.bind(this),
registerOnPostAuth: this.registerOnPostAuth.bind(this),
+ registerOnPreResponse: this.registerOnPreResponse.bind(this),
createCookieSessionStorageFactory: (cookieOptions: SessionStorageCookieOptions) =>
this.createCookieSessionStorageFactory(cookieOptions, config.basePath),
registerAuth: this.registerAuth.bind(this),
@@ -232,6 +234,14 @@ export class HttpServer {
this.server.ext('onRequest', adoptToHapiOnPreAuthFormat(fn, this.log));
}
+ private registerOnPreResponse(fn: OnPreResponseHandler) {
+ if (this.server === undefined) {
+ throw new Error('Server is not created yet');
+ }
+
+ this.server.ext('onPreResponse', adoptToHapiOnPreResponseFormat(fn, this.log));
+ }
+
private async createCookieSessionStorageFactory(
cookieOptions: SessionStorageCookieOptions,
basePath?: string
@@ -289,39 +299,9 @@ export class HttpServer {
// https://github.com/hapijs/hapi/blob/master/API.md#-serverauthdefaultoptions
this.server.auth.default('session');
- this.server.ext('onPreResponse', (request, t) => {
+ this.registerOnPreResponse((request, preResponseInfo, t) => {
const authResponseHeaders = this.authResponseHeaders.get(request);
- this.extendResponseWithHeaders(request, authResponseHeaders);
- return t.continue;
- });
- }
-
- private extendResponseWithHeaders(request: Request, headers?: ResponseHeaders) {
- const response = request.response;
- if (!headers || !response) return;
-
- if (response instanceof Error) {
- this.findHeadersIntersection(response.output.headers, headers);
- // hapi wraps all error response in Boom object internally
- response.output.headers = {
- ...response.output.headers,
- ...(headers as any), // hapi types don't specify string[] as valid value
- };
- } else {
- for (const [headerName, headerValue] of Object.entries(headers)) {
- this.findHeadersIntersection(response.headers, headers);
- response.header(headerName, headerValue as any); // hapi types don't specify string[] as valid value
- }
- }
- }
-
- // NOTE: responseHeaders contains not a full list of response headers, but only explicitly set on a response object.
- // any headers added by hapi internally, like `content-type`, `content-length`, etc. do not present here.
- private findHeadersIntersection(responseHeaders: ResponseHeaders, headers: ResponseHeaders) {
- Object.keys(headers).forEach(headerName => {
- if (responseHeaders[headerName] !== undefined) {
- this.log.warn(`Server rewrites a response header [${headerName}].`);
- }
+ return t.next({ headers: authResponseHeaders });
});
}
}
diff --git a/src/core/server/http/http_service.mock.ts b/src/core/server/http/http_service.mock.ts
index c7f6cdb2bb422..444aa04171dbd 100644
--- a/src/core/server/http/http_service.mock.ts
+++ b/src/core/server/http/http_service.mock.ts
@@ -25,6 +25,7 @@ import { OnPreAuthToolkit } from './lifecycle/on_pre_auth';
import { AuthToolkit } from './lifecycle/auth';
import { sessionStorageMock } from './cookie_session_storage.mocks';
import { OnPostAuthToolkit } from './lifecycle/on_post_auth';
+import { OnPreResponseToolkit } from './lifecycle/on_pre_response';
export type HttpServiceSetupMock = jest.Mocked & {
basePath: jest.Mocked;
@@ -51,6 +52,7 @@ const createSetupContractMock = () => {
registerAuth: jest.fn(),
registerOnPostAuth: jest.fn(),
registerRouteHandlerContext: jest.fn(),
+ registerOnPreResponse: jest.fn(),
createRouter: jest.fn().mockImplementation(() => mockRouter.create({})),
basePath: createBasePathMock(),
auth: {
@@ -92,12 +94,17 @@ const createAuthToolkitMock = (): jest.Mocked => ({
authenticated: jest.fn(),
});
+const createOnPreResponseToolkitMock = (): jest.Mocked => ({
+ next: jest.fn(),
+});
+
export const httpServiceMock = {
create: createHttpServiceMock,
createBasePath: createBasePathMock,
createSetupContract: createSetupContractMock,
createOnPreAuthToolkit: createOnPreAuthToolkitMock,
createOnPostAuthToolkit: createOnPostAuthToolkitMock,
+ createOnPreResponseToolkit: createOnPreResponseToolkitMock,
createAuthToolkit: createAuthToolkitMock,
createRouter: mockRouter.create,
};
diff --git a/src/core/server/http/index.ts b/src/core/server/http/index.ts
index f9a3a91ec18ad..21de3945f1044 100644
--- a/src/core/server/http/index.ts
+++ b/src/core/server/http/index.ts
@@ -64,6 +64,12 @@ export {
AuthResultType,
} from './lifecycle/auth';
export { OnPostAuthHandler, OnPostAuthToolkit } from './lifecycle/on_post_auth';
+export {
+ OnPreResponseHandler,
+ OnPreResponseToolkit,
+ OnPreResponseExtensions,
+ OnPreResponseInfo,
+} from './lifecycle/on_pre_response';
export { SessionStorageFactory, SessionStorage } from './session_storage';
export {
SessionStorageCookieOptions,
diff --git a/src/core/server/http/integration_tests/lifecycle.test.ts b/src/core/server/http/integration_tests/lifecycle.test.ts
index 2a32db77377a4..b16352838fad1 100644
--- a/src/core/server/http/integration_tests/lifecycle.test.ts
+++ b/src/core/server/http/integration_tests/lifecycle.test.ts
@@ -161,7 +161,7 @@ describe('OnPreAuth', () => {
expect(result.header['www-authenticate']).toBe('challenge');
});
- it("doesn't expose error details if interceptor throws", async () => {
+ it('does not expose error details if interceptor throws', async () => {
const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
@@ -734,7 +734,7 @@ describe('Auth', () => {
expect(loggingServiceMock.collect(logger).warn).toMatchInlineSnapshot(`
Array [
Array [
- "Server rewrites a response header [www-authenticate].",
+ "onPreResponseHandler rewrote a response header [www-authenticate].",
],
]
`);
@@ -769,7 +769,7 @@ describe('Auth', () => {
expect(loggingServiceMock.collect(logger).warn).toMatchInlineSnapshot(`
Array [
Array [
- "Server rewrites a response header [www-authenticate].",
+ "onPreResponseHandler rewrote a response header [www-authenticate].",
],
]
`);
@@ -893,3 +893,164 @@ describe('Auth', () => {
.expect(200, { customField: 'undefined' });
});
});
+
+describe('OnPreResponse', () => {
+ it('supports registering response inceptors', async () => {
+ const { registerOnPreResponse, server: innerServer, createRouter } = await server.setup(
+ setupDeps
+ );
+ const router = createRouter('/');
+
+ router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
+
+ const callingOrder: string[] = [];
+ registerOnPreResponse((req, res, t) => {
+ callingOrder.push('first');
+ return t.next();
+ });
+
+ registerOnPreResponse((req, res, t) => {
+ callingOrder.push('second');
+ return t.next();
+ });
+ await server.start();
+
+ await supertest(innerServer.listener)
+ .get('/')
+ .expect(200, 'ok');
+
+ expect(callingOrder).toEqual(['first', 'second']);
+ });
+
+ it('supports additional headers attachments', async () => {
+ const { registerOnPreResponse, server: innerServer, createRouter } = await server.setup(
+ setupDeps
+ );
+ const router = createRouter('/');
+
+ router.get({ path: '/', validate: false }, (context, req, res) =>
+ res.ok({
+ headers: {
+ 'x-my-header': 'foo',
+ },
+ })
+ );
+
+ registerOnPreResponse((req, res, t) =>
+ t.next({
+ headers: {
+ 'x-kibana-header': 'value',
+ },
+ })
+ );
+ await server.start();
+
+ const result = await supertest(innerServer.listener)
+ .get('/')
+ .expect(200);
+
+ expect(result.header['x-kibana-header']).toBe('value');
+ expect(result.header['x-my-header']).toBe('foo');
+ });
+
+ it('logs a warning if interceptor rewrites response header', async () => {
+ const { registerOnPreResponse, server: innerServer, createRouter } = await server.setup(
+ setupDeps
+ );
+ const router = createRouter('/');
+
+ router.get({ path: '/', validate: false }, (context, req, res) =>
+ res.ok({
+ headers: { 'x-kibana-header': 'value' },
+ })
+ );
+ registerOnPreResponse((req, res, t) =>
+ t.next({
+ headers: { 'x-kibana-header': 'value' },
+ })
+ );
+ await server.start();
+
+ await supertest(innerServer.listener)
+ .get('/')
+ .expect(200);
+
+ expect(loggingServiceMock.collect(logger).warn).toMatchInlineSnapshot(`
+ Array [
+ Array [
+ "onPreResponseHandler rewrote a response header [x-kibana-header].",
+ ],
+ ]
+ `);
+ });
+
+ it("doesn't expose error details if interceptor throws", async () => {
+ const { registerOnPreResponse, server: innerServer, createRouter } = await server.setup(
+ setupDeps
+ );
+ const router = createRouter('/');
+
+ router.get({ path: '/', validate: false }, (context, req, res) => res.ok(undefined));
+ registerOnPreResponse((req, res, t) => {
+ throw new Error('reason');
+ });
+ await server.start();
+
+ const result = await supertest(innerServer.listener)
+ .get('/')
+ .expect(500);
+
+ expect(result.body.message).toBe('An internal server error occurred.');
+ expect(loggingServiceMock.collect(logger).error).toMatchInlineSnapshot(`
+ Array [
+ Array [
+ [Error: reason],
+ ],
+ ]
+ `);
+ });
+
+ it('returns internal error if interceptor returns unexpected result', async () => {
+ const { registerOnPreResponse, server: innerServer, createRouter } = await server.setup(
+ setupDeps
+ );
+ const router = createRouter('/');
+
+ router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
+ registerOnPreResponse((req, res, t) => ({} as any));
+ await server.start();
+
+ const result = await supertest(innerServer.listener)
+ .get('/')
+ .expect(500);
+
+ expect(result.body.message).toBe('An internal server error occurred.');
+ expect(loggingServiceMock.collect(logger).error).toMatchInlineSnapshot(`
+ Array [
+ Array [
+ [Error: Unexpected result from OnPreResponse. Expected OnPreResponseResult, but given: [object Object].],
+ ],
+ ]
+ `);
+ });
+
+ it('cannot change response statusCode', async () => {
+ const { registerOnPreResponse, server: innerServer, createRouter } = await server.setup(
+ setupDeps
+ );
+ const router = createRouter('/');
+
+ registerOnPreResponse((req, res, t) => {
+ res.statusCode = 500;
+ return t.next();
+ });
+
+ router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
+
+ await server.start();
+
+ await supertest(innerServer.listener)
+ .get('/')
+ .expect(200);
+ });
+});
diff --git a/src/core/server/http/lifecycle/on_pre_response.ts b/src/core/server/http/lifecycle/on_pre_response.ts
new file mode 100644
index 0000000000000..45d7478df9805
--- /dev/null
+++ b/src/core/server/http/lifecycle/on_pre_response.ts
@@ -0,0 +1,155 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Lifecycle, Request, ResponseToolkit as HapiResponseToolkit } from 'hapi';
+import Boom from 'boom';
+import { Logger } from '../../logging';
+
+import { HapiResponseAdapter, KibanaRequest, ResponseHeaders } from '../router';
+
+enum ResultType {
+ next = 'next',
+}
+
+interface Next {
+ type: ResultType.next;
+ headers?: ResponseHeaders;
+}
+
+/**
+ * @internal
+ */
+type OnPreResponseResult = Next;
+
+/**
+ * Additional data to extend a response.
+ * @public
+ */
+export interface OnPreResponseExtensions {
+ /** additional headers to attach to the response */
+ headers?: ResponseHeaders;
+}
+
+/**
+ * Response status code.
+ * @public
+ */
+export interface OnPreResponseInfo {
+ statusCode: number;
+}
+
+const preResponseResult = {
+ next(responseExtensions?: OnPreResponseExtensions): OnPreResponseResult {
+ return { type: ResultType.next, headers: responseExtensions?.headers };
+ },
+ isNext(result: OnPreResponseResult): result is Next {
+ return result && result.type === ResultType.next;
+ },
+};
+
+/**
+ * A tool set defining an outcome of OnPreAuth interceptor for incoming request.
+ * @public
+ */
+export interface OnPreResponseToolkit {
+ /** To pass request to the next handler */
+ next: (responseExtensions?: OnPreResponseExtensions) => OnPreResponseResult;
+}
+
+const toolkit: OnPreResponseToolkit = {
+ next: preResponseResult.next,
+};
+
+/**
+ * See {@link OnPreAuthToolkit}.
+ * @public
+ */
+export type OnPreResponseHandler = (
+ request: KibanaRequest,
+ preResponse: OnPreResponseInfo,
+ toolkit: OnPreResponseToolkit
+) => OnPreResponseResult | Promise;
+
+/**
+ * @public
+ * Adopt custom request interceptor to Hapi lifecycle system.
+ * @param fn - an extension point allowing to perform custom logic for
+ * incoming HTTP requests.
+ */
+export function adoptToHapiOnPreResponseFormat(fn: OnPreResponseHandler, log: Logger) {
+ return async function interceptPreResponse(
+ request: Request,
+ responseToolkit: HapiResponseToolkit
+ ): Promise {
+ const response = request.response;
+
+ try {
+ if (response) {
+ const statusCode: number = isBoom(response)
+ ? response.output.statusCode
+ : response.statusCode;
+
+ const result = await fn(KibanaRequest.from(request), { statusCode }, toolkit);
+ if (!preResponseResult.isNext(result)) {
+ throw new Error(
+ `Unexpected result from OnPreResponse. Expected OnPreResponseResult, but given: ${result}.`
+ );
+ }
+ if (result.headers) {
+ if (isBoom(response)) {
+ findHeadersIntersection(response.output.headers, result.headers, log);
+ // hapi wraps all error response in Boom object internally
+ response.output.headers = {
+ ...response.output.headers,
+ ...(result.headers as any), // hapi types don't specify string[] as valid value
+ };
+ } else {
+ for (const [headerName, headerValue] of Object.entries(result.headers)) {
+ findHeadersIntersection(response.headers, result.headers, log);
+ response.header(headerName, headerValue as any); // hapi types don't specify string[] as valid value
+ }
+ }
+ }
+ }
+ } catch (error) {
+ log.error(error);
+ const hapiResponseAdapter = new HapiResponseAdapter(responseToolkit);
+ return hapiResponseAdapter.toInternalError();
+ }
+ return responseToolkit.continue;
+ };
+}
+
+function isBoom(response: any): response is Boom {
+ return response instanceof Boom;
+}
+
+// NOTE: responseHeaders contains not a full list of response headers, but only explicitly set on a response object.
+// any headers added by hapi internally, like `content-type`, `content-length`, etc. are not present here.
+function findHeadersIntersection(
+ responseHeaders: ResponseHeaders,
+ headers: ResponseHeaders,
+ log: Logger
+) {
+ Object.keys(headers).forEach(headerName => {
+ if (responseHeaders[headerName] !== undefined) {
+ log.warn(`onPreResponseHandler rewrote a response header [${headerName}].`);
+ }
+ });
+}
diff --git a/src/core/server/http/types.ts b/src/core/server/http/types.ts
index 2c3dfedd1d181..94c1982a18c0a 100644
--- a/src/core/server/http/types.ts
+++ b/src/core/server/http/types.ts
@@ -24,6 +24,7 @@ import { SessionStorageFactory } from './session_storage';
import { AuthenticationHandler } from './lifecycle/auth';
import { OnPreAuthHandler } from './lifecycle/on_pre_auth';
import { OnPostAuthHandler } from './lifecycle/on_post_auth';
+import { OnPreResponseHandler } from './lifecycle/on_pre_response';
import { IBasePath } from './base_path_service';
import { PluginOpaqueId, RequestHandlerContext } from '..';
@@ -163,6 +164,18 @@ export interface HttpServiceSetup {
*/
registerOnPostAuth: (handler: OnPostAuthHandler) => void;
+ /**
+ * To define custom logic to perform for the server response.
+ *
+ * @remarks
+ * Doesn't provide the whole response object.
+ * Supports extending response with custom headers.
+ * See {@link OnPreResponseHandler}.
+ *
+ * @param handler {@link OnPreResponseHandler} - function to call.
+ */
+ registerOnPreResponse: (handler: OnPreResponseHandler) => void;
+
/**
* Access or manipulate the Kibana base path
* See {@link IBasePath}.
diff --git a/src/core/server/index.ts b/src/core/server/index.ts
index efff85142c3e4..57156322e2849 100644
--- a/src/core/server/index.ts
+++ b/src/core/server/index.ts
@@ -105,6 +105,10 @@ export {
OnPreAuthToolkit,
OnPostAuthHandler,
OnPostAuthToolkit,
+ OnPreResponseHandler,
+ OnPreResponseToolkit,
+ OnPreResponseExtensions,
+ OnPreResponseInfo,
RedirectResponseOptions,
RequestHandler,
RequestHandlerContextContainer,
diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts
index 5d111884144c1..fcf0c45c17db8 100644
--- a/src/core/server/legacy/legacy_service.ts
+++ b/src/core/server/legacy/legacy_service.ts
@@ -270,6 +270,7 @@ export class LegacyService implements CoreService {
registerOnPreAuth: setupDeps.core.http.registerOnPreAuth,
registerAuth: setupDeps.core.http.registerAuth,
registerOnPostAuth: setupDeps.core.http.registerOnPostAuth,
+ registerOnPreResponse: setupDeps.core.http.registerOnPreResponse,
basePath: setupDeps.core.http.basePath,
isTlsEnabled: setupDeps.core.http.isTlsEnabled,
},
diff --git a/src/core/server/logging/logging_service.test.ts b/src/core/server/logging/logging_service.test.ts
index 380488ff9f62d..c58103cca5f8d 100644
--- a/src/core/server/logging/logging_service.test.ts
+++ b/src/core/server/logging/logging_service.test.ts
@@ -23,6 +23,10 @@ jest.mock('fs', () => ({
createWriteStream: jest.fn(() => ({ write: mockStreamWrite })),
}));
+jest.mock('../../../legacy/server/logging/rotate', () => ({
+ setupLoggingRotate: jest.fn().mockImplementation(() => Promise.resolve({})),
+}));
+
const timestamp = new Date(Date.UTC(2012, 1, 1));
let mockConsoleLog: jest.SpyInstance;
diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts
index 8f864dda6b9f3..c07caaa04ba52 100644
--- a/src/core/server/mocks.ts
+++ b/src/core/server/mocks.ts
@@ -90,6 +90,7 @@ function createCoreSetupMock() {
registerOnPreAuth: httpService.registerOnPreAuth,
registerAuth: httpService.registerAuth,
registerOnPostAuth: httpService.registerOnPostAuth,
+ registerOnPreResponse: httpService.registerOnPreResponse,
basePath: httpService.basePath,
isTlsEnabled: httpService.isTlsEnabled,
createRouter: jest.fn(),
diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts
index dfd1052bbec75..6829784e6e0a1 100644
--- a/src/core/server/plugins/plugin_context.ts
+++ b/src/core/server/plugins/plugin_context.ts
@@ -159,6 +159,7 @@ export function createPluginSetupContext(
registerOnPreAuth: deps.http.registerOnPreAuth,
registerAuth: deps.http.registerAuth,
registerOnPostAuth: deps.http.registerOnPostAuth,
+ registerOnPreResponse: deps.http.registerOnPreResponse,
basePath: deps.http.basePath,
isTlsEnabled: deps.http.isTlsEnabled,
},
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index 7e1226aa7238b..c855e04e420f7 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -697,6 +697,7 @@ export interface HttpServiceSetup {
registerAuth: (handler: AuthenticationHandler) => void;
registerOnPostAuth: (handler: OnPostAuthHandler) => void;
registerOnPreAuth: (handler: OnPreAuthHandler) => void;
+ registerOnPreResponse: (handler: OnPreResponseHandler) => void;
registerRouteHandlerContext: (contextName: T, provider: RequestHandlerContextProvider) => RequestHandlerContextContainer;
}
@@ -976,6 +977,27 @@ export interface OnPreAuthToolkit {
rewriteUrl: (url: string) => OnPreAuthResult;
}
+// @public
+export interface OnPreResponseExtensions {
+ headers?: ResponseHeaders;
+}
+
+// Warning: (ae-forgotten-export) The symbol "OnPreResponseResult" needs to be exported by the entry point index.d.ts
+//
+// @public
+export type OnPreResponseHandler = (request: KibanaRequest, preResponse: OnPreResponseInfo, toolkit: OnPreResponseToolkit) => OnPreResponseResult | Promise;
+
+// @public
+export interface OnPreResponseInfo {
+ // (undocumented)
+ statusCode: number;
+}
+
+// @public
+export interface OnPreResponseToolkit {
+ next: (responseExtensions?: OnPreResponseExtensions) => OnPreResponseResult;
+}
+
// @public (undocumented)
export interface PackageInfo {
// (undocumented)
diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker
index 0c8faf47411d4..d1734e836d983 100755
--- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker
+++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker
@@ -42,6 +42,11 @@ kibana_vars=(
kibana.index
logging.dest
logging.quiet
+ logging.rotate.enabled
+ logging.rotate.everyBytes
+ logging.rotate.keepFiles
+ logging.rotate.pollingInterval
+ logging.rotate.usePolling
logging.silent
logging.useUTC
logging.verbose
diff --git a/src/legacy/core_plugins/console/index.ts b/src/legacy/core_plugins/console/index.ts
index c4e6a77b7d859..cec6d0a4219ae 100644
--- a/src/legacy/core_plugins/console/index.ts
+++ b/src/legacy/core_plugins/console/index.ts
@@ -19,7 +19,7 @@
import Boom from 'boom';
import { first } from 'rxjs/operators';
-import { resolve, join, sep } from 'path';
+import { resolve, join } from 'path';
import url from 'url';
import { has, isEmpty, head, pick } from 'lodash';
@@ -51,9 +51,7 @@ function filterHeaders(originalHeaders: any, headersToKeep: any) {
// eslint-disable-next-line
export default function(kibana: any) {
- const modules = resolve(__dirname, 'public/webpackShims/');
- const quarantinedSrc = resolve(__dirname, 'public/quarantined/src/');
- const npSrc = resolve(__dirname, 'np_ready/public');
+ const npSrc = resolve(__dirname, 'public/np_ready');
let defaultVars: any;
return new kibana.Plugin({
@@ -180,16 +178,10 @@ export default function(kibana: any) {
},
uiExports: {
- devTools: [`${npSrc}/legacy`],
- styleSheetPaths: resolve(__dirname, 'public/quarantined/index.scss'),
-
+ devTools: [resolve(__dirname, 'public/legacy')],
+ styleSheetPaths: resolve(npSrc, 'application/styles/index.scss'),
injectDefaultVars: () => defaultVars,
-
- noParse: [
- join(modules, 'ace' + sep),
- join(modules, 'moment_src/moment' + sep),
- join(quarantinedSrc, 'sense_editor/mode/worker.js'),
- ],
+ noParse: [join(npSrc, 'application/models/legacy_core_editor/mode/worker/worker.js')],
},
} as any);
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.test.ts b/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.test.ts
deleted file mode 100644
index 0eb6a8fec4f86..0000000000000
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.test.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import sinon from 'sinon';
-import $ from 'jquery';
-
-import { loadRemoteState } from './load_remote_editor_state';
-
-describe('[Legacy Console] loading remote editor state', () => {
- const sandbox = sinon.createSandbox();
-
- let inputMock: any;
- let ajaxDoneStub: any;
- beforeEach(() => {
- ajaxDoneStub = sinon.stub();
- sandbox.stub($, 'ajax').returns({ done: ajaxDoneStub } as any);
-
- inputMock = {
- update: sinon.stub(),
- moveToNextRequestEdge: sinon.stub(),
- highlightCurrentRequestsAndUpdateActionBar: sinon.stub(),
- updateActionsBar: sinon.stub(),
- getSession: sinon.stub().returns({ on() {} }),
- };
- });
-
- afterEach(() => {
- sandbox.restore();
- });
-
- it('correctly loads state from any external HTTPS links.', () => {
- const mockContent = {};
- ajaxDoneStub.yields(mockContent);
-
- loadRemoteState({
- input: inputMock,
- url: 'https://state.link.com/content',
- });
-
- sinon.assert.calledOnce($.ajax as any);
- sinon.assert.calledWithExactly($.ajax as any, {
- url: 'https://state.link.com/content',
- dataType: 'text',
- kbnXsrfToken: false,
- headers: {},
- });
-
- sinon.assert.calledTwice(inputMock.moveToNextRequestEdge);
- sinon.assert.calledWithExactly(inputMock.moveToNextRequestEdge, true);
- sinon.assert.calledOnce(inputMock.highlightCurrentRequestsAndUpdateActionBar);
- sinon.assert.calledOnce(inputMock.updateActionsBar);
- sinon.assert.calledOnce(inputMock.update);
- sinon.assert.calledWithExactly(inputMock.update, sinon.match.same(mockContent));
- });
-
- it('correctly loads state from GitHub API HTTPS links.', () => {
- const mockContent = {};
- ajaxDoneStub.yields(mockContent);
-
- loadRemoteState({
- input: inputMock,
- url: 'https://api.github.com/content',
- });
-
- sinon.assert.calledOnce($.ajax as any);
- sinon.assert.calledWithExactly($.ajax as any, {
- url: 'https://api.github.com/content',
- dataType: 'text',
- kbnXsrfToken: false,
- headers: { Accept: 'application/vnd.github.v3.raw' },
- });
-
- sinon.assert.calledTwice(inputMock.moveToNextRequestEdge);
- sinon.assert.calledWithExactly(inputMock.moveToNextRequestEdge, true);
- sinon.assert.calledOnce(inputMock.highlightCurrentRequestsAndUpdateActionBar);
- sinon.assert.calledOnce(inputMock.updateActionsBar);
- sinon.assert.calledOnce(inputMock.update);
- sinon.assert.calledWithExactly(inputMock.update, sinon.match.same(mockContent));
- });
-});
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.ts b/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.ts
deleted file mode 100644
index b2f475036c5da..0000000000000
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import $ from 'jquery';
-
-// @ts-ignore
-// import mappings from '../../../../../../public/quarantined/src/mappings';
-
-/* eslint-disable no-console */
-
-export interface InitializationArgs {
- url: string;
- input: any;
-}
-
-export function loadRemoteState({ url, input }: InitializationArgs) {
- const loadFrom = {
- url,
- // Having dataType here is required as it doesn't allow jQuery to `eval` content
- // coming from the external source thereby preventing XSS attack.
- dataType: 'text',
- kbnXsrfToken: false,
- headers: {},
- };
-
- if (/https?:\/\/api.github.com/.test(url)) {
- loadFrom.headers = { Accept: 'application/vnd.github.v3.raw' };
- }
-
- $.ajax(loadFrom).done(data => {
- input.update(data);
- input.moveToNextRequestEdge(true);
- input.highlightCurrentRequestsAndUpdateActionBar();
- input.updateActionsBar();
- });
- input.moveToNextRequestEdge(true);
-}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_menu_actions.ts b/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_menu_actions.ts
deleted file mode 100644
index b728df615fc9d..0000000000000
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_menu_actions.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// @ts-ignore
-import { getEndpointFromPosition } from '../../../../../../public/quarantined/src/autocomplete';
-
-export function autoIndent(editor: any, event: any) {
- editor.autoIndent();
- event.preventDefault();
- editor.focus();
-}
-
-export function getDocumentation(editor: any, docLinkVersion: string): Promise {
- return new Promise(resolve => {
- editor.getRequestsInRange((requests: any) => {
- if (!requests || requests.length === 0) {
- resolve(null);
- return;
- }
- const position = requests[0].range.end;
- position.column = position.column - 1;
- const endpoint = getEndpointFromPosition(editor, position, editor.parser);
- if (endpoint && endpoint.documentation && endpoint.documentation.indexOf('http') !== -1) {
- const nextDocumentation = endpoint.documentation
- .replace('/master/', `/${docLinkVersion}/`)
- .replace('/current/', `/${docLinkVersion}/`);
- resolve(nextDocumentation);
- } else {
- resolve(null);
- }
- });
- });
-}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.test.ts b/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.test.ts
deleted file mode 100644
index 0dc1bcc96ddee..0000000000000
--- a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.test.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { Range as AceRange } from 'brace';
-import { LegacyEditor } from './legacy_editor';
-
-describe('Legacy Editor', () => {
- const aceMock: any = {
- getValue() {
- return 'ok';
- },
-
- getCursorPosition() {
- return {
- row: 1,
- column: 1,
- };
- },
-
- getSession() {
- return {
- replace(range: AceRange, value: string) {},
- getLine(n: number) {
- return 'line';
- },
- doc: {
- getTextRange(r: any) {
- return '';
- },
- },
- getState(n: number) {
- return n;
- },
- };
- },
- };
-
- // This is to ensure that we are correctly importing Ace's Range component
- it('smoke tests for updates to ranges', () => {
- const legacyEditor = new LegacyEditor(aceMock);
- legacyEditor.getValueInRange({
- start: { lineNumber: 1, column: 1 },
- end: { lineNumber: 2, column: 2 },
- });
- legacyEditor.replace(
- {
- start: { lineNumber: 1, column: 1 },
- end: { lineNumber: 2, column: 2 },
- },
- 'test!'
- );
- });
-});
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.ts b/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.ts
deleted file mode 100644
index f8c3f425a1032..0000000000000
--- a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import ace from 'brace';
-import { Editor as IAceEditor } from 'brace';
-import { CoreEditor, Position, Range, Token, TokensProvider } from '../../types';
-import { AceTokensProvider } from '../../lib/ace_token_provider';
-
-const _AceRange = ace.acequire('ace/range').Range;
-
-export class LegacyEditor implements CoreEditor {
- constructor(private readonly editor: IAceEditor) {}
-
- getLineState(lineNumber: number) {
- const session = this.editor.getSession();
- return session.getState(lineNumber - 1);
- }
-
- getValueInRange({ start, end }: Range): string {
- const session = this.editor.getSession();
- const aceRange = new _AceRange(
- start.lineNumber - 1,
- start.column - 1,
- end.lineNumber - 1,
- end.column - 1
- );
- return session.doc.getTextRange(aceRange);
- }
-
- getTokenProvider(): TokensProvider {
- return new AceTokensProvider(this.editor.getSession());
- }
-
- getValue(): string {
- return this.editor.getValue();
- }
-
- getLineValue(lineNumber: number): string {
- const session = this.editor.getSession();
- return session.getLine(lineNumber - 1);
- }
-
- getCurrentPosition(): Position {
- const cursorPosition = this.editor.getCursorPosition();
- return {
- lineNumber: cursorPosition.row + 1,
- column: cursorPosition.column + 1,
- };
- }
-
- clearSelection(): void {
- this.editor.clearSelection();
- }
-
- getTokenAt(pos: Position): Token | null {
- const provider = this.getTokenProvider();
- return provider.getTokenAt(pos);
- }
-
- insert(valueOrPos: string | Position, value?: string): void {
- if (typeof valueOrPos === 'string') {
- this.editor.insert(valueOrPos);
- return;
- }
- const document = this.editor.getSession().getDocument();
- document.insert(
- {
- column: valueOrPos.column - 1,
- row: valueOrPos.lineNumber - 1,
- },
- value || ''
- );
- }
-
- moveCursorToPosition(pos: Position): void {
- this.editor.moveCursorToPosition({ row: pos.lineNumber - 1, column: pos.column - 1 });
- }
-
- replace({ start, end }: Range, value: string): void {
- const aceRange = new _AceRange(
- start.lineNumber - 1,
- start.column - 1,
- end.lineNumber - 1,
- end.column - 1
- );
- const session = this.editor.getSession();
- session.replace(aceRange, value);
- }
-
- getLines(startLine: number, endLine: number): string[] {
- const session = this.editor.getSession();
- return session.getLines(startLine - 1, endLine - 1);
- }
-}
diff --git a/src/legacy/core_plugins/console/np_ready/server/.gitkeep b/src/legacy/core_plugins/console/np_ready/server/.gitkeep
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/src/legacy/core_plugins/console/public/README.md b/src/legacy/core_plugins/console/public/README.md
deleted file mode 100644
index 3a53c46143793..0000000000000
--- a/src/legacy/core_plugins/console/public/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-## New Platform (NP) Ready vs Quarantined
-
-We want to move toward more modularised code in the Console app.
-Part of the effort means separating out different console components
-like:
-
-- The language parser
-- The editor rendering component
-- Autocomplete
-- The UI container components
-
-In addition to this effort we want to bring Console in line with NP
-requirements and ensure that we are not using angular and public ui
-in this app anymore.
-
-The quarantined folder contains all of the code that has not been cleared
-for living in the new platform as it has not been properly refactored
-or has dependencies on, for example, UI public.
-
-Over time, the quarantined part of the code should shrink to nothing
-and we should only have NP ready code.
diff --git a/src/legacy/core_plugins/console/np_ready/kibana.json b/src/legacy/core_plugins/console/public/kibana.json
similarity index 59%
rename from src/legacy/core_plugins/console/np_ready/kibana.json
rename to src/legacy/core_plugins/console/public/kibana.json
index ed8e4d8f15830..3363af353912a 100644
--- a/src/legacy/core_plugins/console/np_ready/kibana.json
+++ b/src/legacy/core_plugins/console/public/kibana.json
@@ -2,5 +2,6 @@
"id": "console",
"version": "kibana",
"server": true,
- "ui": true
+ "ui": true,
+ "requiredPlugins": ["home"]
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/legacy.ts b/src/legacy/core_plugins/console/public/legacy.ts
similarity index 62%
rename from src/legacy/core_plugins/console/np_ready/public/legacy.ts
rename to src/legacy/core_plugins/console/public/legacy.ts
index 758ea81be88ad..c456d777187aa 100644
--- a/src/legacy/core_plugins/console/np_ready/public/legacy.ts
+++ b/src/legacy/core_plugins/console/public/legacy.ts
@@ -17,35 +17,35 @@
* under the License.
*/
-import 'brace';
-import 'brace/ext/language_tools';
-import 'brace/ext/searchbox';
-import 'brace/mode/json';
-import 'brace/mode/text';
-
-/* eslint-disable @kbn/eslint/no-restricted-paths */
import { npSetup, npStart } from 'ui/new_platform';
import { I18nContext } from 'ui/i18n';
-/* eslint-enable @kbn/eslint/no-restricted-paths */
+import chrome from 'ui/chrome';
+import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
export interface XPluginSet {
dev_tools: DevToolsSetup;
home: HomePublicPluginSetup;
__LEGACY: {
I18nContext: any;
+ elasticsearchUrl: string;
+ category: FeatureCatalogueCategory;
};
}
-import { plugin } from '.';
-import { DevToolsSetup } from '../../../../../plugins/dev_tools/public';
-import { HomePublicPluginSetup } from '../../../../../plugins/home/public';
+import { plugin } from './np_ready';
+import { DevToolsSetup } from '../../../../plugins/dev_tools/public';
+import { HomePublicPluginSetup } from '../../../../plugins/home/public';
const pluginInstance = plugin({} as any);
-pluginInstance.setup(npSetup.core, {
- ...npSetup.plugins,
- __LEGACY: {
- I18nContext,
- },
-});
-pluginInstance.start(npStart.core);
+(async () => {
+ await pluginInstance.setup(npSetup.core, {
+ ...npSetup.plugins,
+ __LEGACY: {
+ elasticsearchUrl: chrome.getInjected('elasticsearchUrl'),
+ I18nContext,
+ category: FeatureCatalogueCategory.ADMIN,
+ },
+ });
+ await pluginInstance.start(npStart.core);
+})();
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/console_menu.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx
similarity index 98%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/console_menu.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx
index fd87c0b94ef5b..7842c15be267f 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/components/console_menu.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx
@@ -25,7 +25,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
interface Props {
- getCurl: (cb: (text: string) => void) => void;
+ getCurl: () => Promise;
getDocumentation: () => Promise;
autoIndent: (ev?: React.MouseEvent) => void;
addNotification?: (opts: { title: string }) => void;
@@ -48,7 +48,7 @@ export class ConsoleMenu extends Component {
mouseEnter = () => {
if (this.state.isPopoverOpen) return;
- this.props.getCurl(text => {
+ this.props.getCurl().then(text => {
this.setState({ curlCode: text });
});
};
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/editor_example.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx
similarity index 80%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/editor_example.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx
index 01bd3fcd78e53..ea08a06a9e39b 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/components/editor_example.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx
@@ -20,9 +20,7 @@
import React, { useEffect } from 'react';
// @ts-ignore
import exampleText from 'raw-loader!../constants/help_example.txt';
-import $ from 'jquery';
-// @ts-ignore
-import SenseEditor from '../../../../public/quarantined/src/sense_editor/editor';
+import { createReadOnlyAceEditor } from '../models/legacy_core_editor';
interface EditorExampleProps {
panel: string;
@@ -32,11 +30,9 @@ export function EditorExample(props: EditorExampleProps) {
const elemId = `help-example-${props.panel}`;
useEffect(() => {
- const el = $(`#${elemId}`);
- el.text(exampleText.trim());
- const editor = new SenseEditor(el);
- editor.setReadOnly(true);
- editor.$blockScrolling = Infinity;
+ const el = document.querySelector(`#${elemId}`)!;
+ el.textContent = exampleText.trim();
+ const editor = createReadOnlyAceEditor(el);
return () => {
editor.destroy();
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/help_panel.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/help_panel.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/help_panel.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/help_panel.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/components/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/components/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/settings_modal.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/settings_modal.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/components/resizer.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/components/resizer.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/components/resizer.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/components/resizer.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel_container.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel_container.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel_container.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel_container.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/context.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/context.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/context.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/registry.ts b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/registry.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/registry.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/registry.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/split_panel.test.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/split_panel.test.tsx
similarity index 98%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/split_panel.test.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/split_panel.test.tsx
index e60912a29355b..304535421a78a 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/split_panel.test.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/split_panel.test.tsx
@@ -22,7 +22,7 @@ import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { spy } from 'sinon';
-import { PanelsContainer, Panel } from '.';
+import { PanelsContainer, Panel } from './index';
const testComponentA = A
;
const testComponentB = B
;
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/top_nav_menu.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/top_nav_menu.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/top_nav_menu.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/top_nav_menu.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/welcome_panel.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/welcome_panel.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/components/welcome_panel.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/components/welcome_panel.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/constants/help_example.txt b/src/legacy/core_plugins/console/public/np_ready/application/constants/help_example.txt
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/constants/help_example.txt
rename to src/legacy/core_plugins/console/public/np_ready/application/constants/help_example.txt
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/console_history.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx
similarity index 98%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/console_history.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx
index 30966a2f77e1d..8ec8b9c61bf03 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/console_history.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx
@@ -175,7 +175,7 @@ export function ConsoleHistory({ close }: Props) {
role="option"
onMouseEnter={() => setViewingReq(req)}
onMouseLeave={() => setViewingReq(selectedReq.current)}
- onDoubleClick={restoreRequestFromHistory}
+ onDoubleClick={() => restoreRequestFromHistory(selectedReq.current)}
aria-label={i18n.translate('console.historyPage.itemOfRequestListAriaLabel', {
defaultMessage: 'Request: {historyItem}',
values: { historyItem: reqDescription },
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/history_viewer.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx
similarity index 83%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/history_viewer.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx
index 6fbb46bba6212..2a5ffee149b92 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/history_viewer.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx
@@ -19,13 +19,14 @@
import React, { useEffect, useRef } from 'react';
import { i18n } from '@kbn/i18n';
-import $ from 'jquery';
import { DevToolsSettings } from '../../../services';
import { subscribeResizeChecker } from '../editor/legacy/subscribe_console_resize_checker';
// @ts-ignore
-import SenseEditor from '../../../../../public/quarantined/src/sense_editor/editor';
+import * as InputMode from '../../models/legacy_core_editor/mode/input';
+const inputMode = new InputMode.Mode();
+import * as editor from '../../models/legacy_core_editor';
import { applyCurrentSettings } from '../editor/legacy/console_editor/apply_editor_settings';
interface Props {
@@ -35,13 +36,11 @@ interface Props {
export function HistoryViewer({ settings, req }: Props) {
const divRef = useRef(null);
- const viewerRef = useRef(null);
+ const viewerRef = useRef(null);
useEffect(() => {
- const viewer = new SenseEditor($(divRef.current!));
+ const viewer = editor.createReadOnlyAceEditor(divRef.current!);
viewerRef.current = viewer;
- viewer.renderer.setShowPrintMargin(false);
- viewer.$blockScrolling = Infinity;
const unsubscribe = subscribeResizeChecker(divRef.current!, viewer);
return () => unsubscribe();
}, []);
@@ -54,13 +53,14 @@ export function HistoryViewer({ settings, req }: Props) {
const { current: viewer } = viewerRef;
if (req) {
const s = req.method + ' ' + req.endpoint + '\n' + (req.data || '');
- viewer.setValue(s);
+ viewer.update(s, inputMode);
viewer.clearSelection();
} else {
- viewer.getSession().setValue(
+ viewer.update(
i18n.translate('console.historyPage.noHistoryTextMessage', {
defaultMessage: 'No history available',
- })
+ }),
+ inputMode
);
}
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/editor.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/editor.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/index.ts
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts
new file mode 100644
index 0000000000000..f9cfadf7fe34b
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts
@@ -0,0 +1,37 @@
+/*
+ * 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 { DevToolsSettings } from '../../../../../services';
+import { CoreEditor } from '../../../../../types';
+import { CustomAceEditor } from '../../../../models/legacy_core_editor';
+
+export function applyCurrentSettings(
+ editor: CoreEditor | CustomAceEditor,
+ settings: DevToolsSettings
+) {
+ if ((editor as any).setStyles) {
+ (editor as CoreEditor).setStyles({
+ wrapLines: settings.wrapMode,
+ fontSize: settings.fontSize + 'px',
+ });
+ } else {
+ (editor as CustomAceEditor).getSession().setUseWrapMode(settings.wrapMode);
+ (editor as CustomAceEditor).container.style.fontSize = settings.fontSize + 'px';
+ }
+}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx
similarity index 75%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx
index a9db5cfcac3eb..5df72c0f03496 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx
@@ -21,24 +21,27 @@ jest.mock('../../../../contexts/editor_context/editor_registry.ts', () => ({
instance: {
setInputEditor: () => {},
getInputEditor: () => ({
- getRequestsInRange: (cb: any) => cb([{ test: 'test' }]),
+ getRequestsInRange: async () => [{ test: 'test' }],
}),
},
}));
jest.mock('../../../../components/editor_example.tsx', () => {});
-jest.mock('../../../../../../../public/quarantined/src/mappings.js', () => ({
+jest.mock('../../../../../lib/mappings/mappings', () => ({
retrieveAutoCompleteInfo: () => {},
clearSubscriptions: () => {},
}));
-jest.mock('../../../../../../../public/quarantined/src/input.ts', () => {
+jest.mock('../../../../models/sense_editor', () => {
return {
- initializeEditor: () => ({
- $el: {
- css: () => {},
- },
- focus: () => {},
- update: () => {},
- getSession: () => ({ on: () => {}, setUseWrapMode: () => {} }),
+ create: () => ({
+ getCoreEditor: () => ({
+ registerKeyboardShortcut: jest.fn(),
+ setStyles: jest.fn(),
+ getContainer: () => ({
+ focus: () => {},
+ }),
+ on: jest.fn(),
+ }),
+ update: jest.fn(),
commands: {
addCommand: () => {},
},
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx
similarity index 78%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx
index b99249b2b0016..442ed330e9b7a 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx
@@ -21,8 +21,6 @@ import React, { CSSProperties, useCallback, useEffect, useRef, useState } from '
import { EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import $ from 'jquery';
-
import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useServicesContext, useEditorReadContext } from '../../../../contexts';
import { useUIAceKeyboardMode } from '../use_ui_ace_keyboard_mode';
@@ -34,17 +32,11 @@ import { applyCurrentSettings } from './apply_editor_settings';
import { useSendCurrentRequestToES, useSetInputEditor } from '../../../../hooks';
+import * as senseEditor from '../../../../models/sense_editor';
// @ts-ignore
-import { initializeEditor } from '../../../../../../../public/quarantined/src/input';
-// @ts-ignore
-import mappings from '../../../../../../../public/quarantined/src/mappings';
+import mappings from '../../../../../lib/mappings/mappings';
import { subscribeResizeChecker } from '../subscribe_console_resize_checker';
-import { loadRemoteState } from './load_remote_editor_state';
-
-export interface EditorProps {
- previousStateLocation?: 'stored' | string;
-}
const abs: CSSProperties = {
position: 'absolute',
@@ -61,10 +53,11 @@ const DEFAULT_INPUT_VALUE = `GET _search
}
}`;
-function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
+function EditorUI() {
const {
services: { history, notifications },
docLinkVersion,
+ elasticsearchUrl,
} = useServicesContext();
const { settings } = useEditorReadContext();
@@ -72,8 +65,7 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
const sendCurrentRequestToES = useSendCurrentRequestToES();
const editorRef = useRef(null);
- const actionsRef = useRef(null);
- const editorInstanceRef = useRef(null);
+ const editorInstanceRef = useRef(null);
const [textArea, setTextArea] = useState(null);
useUIAceKeyboardMode(textArea);
@@ -87,24 +79,18 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
}, [docLinkVersion]);
useEffect(() => {
- const $editor = $(editorRef.current!);
- const $actions = $(actionsRef.current!);
- editorInstanceRef.current = initializeEditor($editor, $actions);
-
- if (previousStateLocation === 'stored') {
- const { content } = history.getSavedEditorState() || {
- content: DEFAULT_INPUT_VALUE,
- };
- editorInstanceRef.current.update(content);
- } else {
- loadRemoteState({ url: previousStateLocation, input: editorInstanceRef.current });
- }
+ editorInstanceRef.current = senseEditor.create(editorRef.current!);
+
+ const { content: text } = history.getSavedEditorState() || {
+ content: DEFAULT_INPUT_VALUE,
+ };
+ editorInstanceRef.current.update(text);
function setupAutosave() {
let timer: number;
const saveDelay = 500;
- editorInstanceRef.current.getSession().on('change', function onChange() {
+ editorInstanceRef.current!.getCoreEditor().on('change', () => {
if (timer) {
clearTimeout(timer);
}
@@ -114,7 +100,7 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
function saveCurrentState() {
try {
- const content = editorInstanceRef.current.getValue();
+ const content = editorInstanceRef.current!.getCoreEditor().getValue();
history.updateCurrentState(content);
} catch (e) {
// Ignoring saving error
@@ -128,7 +114,7 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
const unsubscribeResizer = subscribeResizeChecker(
editorRef.current!,
- editorInstanceRef.current
+ editorInstanceRef.current.getCoreEditor()
);
setupAutosave();
@@ -136,17 +122,20 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
unsubscribeResizer();
mappings.clearSubscriptions();
};
- }, [history, previousStateLocation, setInputEditor]);
+ }, [history, setInputEditor]);
useEffect(() => {
- applyCurrentSettings(editorInstanceRef.current!, settings);
+ applyCurrentSettings(editorInstanceRef.current!.getCoreEditor(), settings);
// Preserve legacy focus behavior after settings have updated.
- editorInstanceRef.current!.focus();
+ editorInstanceRef
+ .current!.getCoreEditor()
+ .getContainer()
+ .focus();
}, [settings]);
useEffect(() => {
registerCommands({
- input: editorInstanceRef.current,
+ senseEditor: editorInstanceRef.current!,
sendCurrentRequestToES,
openDocumentation,
});
@@ -157,7 +146,6 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
{
- editorInstanceRef.current!.getRequestsAsCURL(cb);
+ getCurl={() => {
+ return editorInstanceRef.current!.getRequestsAsCURL(elasticsearchUrl);
}}
getDocumentation={() => {
return getDocumentation(editorInstanceRef.current!, docLinkVersion);
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor_output.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx
similarity index 78%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor_output.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx
index 3690ea61d5684..b1398d0a19a8f 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor_output.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx
@@ -18,18 +18,14 @@
*/
import React, { useEffect, useRef } from 'react';
-import $ from 'jquery';
-
-// @ts-ignore
-import { initializeOutput } from '../../../../../../../public/quarantined/src/output';
+import { createReadOnlyAceEditor, CustomAceEditor } from '../../../../models/legacy_core_editor';
import {
useServicesContext,
useEditorReadContext,
useRequestReadContext,
} from '../../../../contexts';
-// @ts-ignore
-import utils from '../../../../../../../public/quarantined/src/utils';
+import * as utils from '../../../../../lib/utils/utils';
import { subscribeResizeChecker } from '../subscribe_console_resize_checker';
import { applyCurrentSettings } from './apply_editor_settings';
@@ -45,7 +41,7 @@ function modeForContentType(contentType: string) {
function EditorOutputUI() {
const editorRef = useRef(null);
- const editorInstanceRef = useRef(null);
+ const editorInstanceRef = useRef(null);
const { services } = useServicesContext();
const { settings: readOnlySettings } = useEditorReadContext();
@@ -54,8 +50,7 @@ function EditorOutputUI() {
} = useRequestReadContext();
useEffect(() => {
- const editor$ = $(editorRef.current!);
- editorInstanceRef.current = initializeOutput(editor$, services.settings);
+ editorInstanceRef.current = createReadOnlyAceEditor(editorRef.current!);
const unsubscribe = subscribeResizeChecker(editorRef.current!, editorInstanceRef.current);
return () => {
@@ -64,25 +59,26 @@ function EditorOutputUI() {
}, [services.settings]);
useEffect(() => {
+ const editor = editorInstanceRef.current!;
if (data) {
const mode = modeForContentType(data[0].response.contentType);
- editorInstanceRef.current.session.setMode(mode);
- editorInstanceRef.current.update(
+ editor.session.setMode(mode);
+ editor.update(
data
- .map(d => d.response.value)
+ .map(d => d.response.value as string)
.map(readOnlySettings.tripleQuotes ? utils.expandLiteralStrings : a => a)
.join('\n')
);
} else if (error) {
- editorInstanceRef.current.session.setMode(modeForContentType(error.contentType));
- editorInstanceRef.current.update(error.value);
+ editor.session.setMode(modeForContentType(error.contentType));
+ editor.update(error.value);
} else {
- editorInstanceRef.current.update('');
+ editor.update('');
}
}, [readOnlySettings, data, error]);
useEffect(() => {
- applyCurrentSettings(editorInstanceRef.current, readOnlySettings);
+ applyCurrentSettings(editorInstanceRef.current!, readOnlySettings);
}, [readOnlySettings]);
return (
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts
similarity index 55%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts
index d1605c1aefa56..39621a9cb3dd2 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts
@@ -17,49 +17,60 @@
* under the License.
*/
import { throttle } from 'lodash';
+import { SenseEditor } from '../../../../models/sense_editor';
interface Actions {
- input: any; // TODO: Wrap this in an editor interface
+ senseEditor: SenseEditor;
sendCurrentRequestToES: () => void;
openDocumentation: () => void;
}
-export function registerCommands({ input, sendCurrentRequestToES, openDocumentation }: Actions) {
- const throttledAutoIndent = throttle(() => input.autoIndent(), 500, {
+export function registerCommands({
+ senseEditor,
+ sendCurrentRequestToES,
+ openDocumentation,
+}: Actions) {
+ const throttledAutoIndent = throttle(() => senseEditor.autoIndent(), 500, {
leading: true,
trailing: true,
});
- input.commands.addCommand({
- name: 'send to elasticsearch',
- bindKey: { win: 'Ctrl-Enter', mac: 'Command-Enter' },
- exec: () => sendCurrentRequestToES(),
+ const coreEditor = senseEditor.getCoreEditor();
+
+ coreEditor.registerKeyboardShortcut({
+ keys: { win: 'Ctrl-Enter', mac: 'Command-Enter' },
+ name: 'send to Elasticsearch',
+ fn: () => sendCurrentRequestToES(),
});
- input.commands.addCommand({
+
+ coreEditor.registerKeyboardShortcut({
name: 'open documentation',
- bindKey: { win: 'Ctrl-/', mac: 'Command-/' },
- exec: () => {
+ keys: { win: 'Ctrl-/', mac: 'Command-/' },
+ fn: () => {
openDocumentation();
},
});
- input.commands.addCommand({
+
+ coreEditor.registerKeyboardShortcut({
name: 'auto indent request',
- bindKey: { win: 'Ctrl-I', mac: 'Command-I' },
- exec: () => {
+ keys: { win: 'Ctrl-I', mac: 'Command-I' },
+ fn: () => {
throttledAutoIndent();
},
});
- input.commands.addCommand({
+
+ coreEditor.registerKeyboardShortcut({
name: 'move to previous request start or end',
- bindKey: { win: 'Ctrl-Up', mac: 'Command-Up' },
- exec: () => {
- input.moveToPreviousRequestEdge();
+ keys: { win: 'Ctrl-Up', mac: 'Command-Up' },
+ fn: () => {
+ senseEditor.moveToPreviousRequestEdge();
},
});
- input.commands.addCommand({
+
+ coreEditor.registerKeyboardShortcut({
name: 'move to next request start or end',
- bindKey: { win: 'Ctrl-Down', mac: 'Command-Down' },
- exec: () => {
- input.moveToNextRequestEdge();
+ keys: { win: 'Ctrl-Down', mac: 'Command-Down' },
+ fn: () => {
+ senseEditor.moveToNextRequestEdge(false);
},
});
}
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts
new file mode 100644
index 0000000000000..797ff5744eec3
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+// @ts-ignore
+import { getEndpointFromPosition } from '../../../../lib/autocomplete/autocomplete';
+import { SenseEditor } from '../../../models/sense_editor';
+
+export async function autoIndent(editor: SenseEditor, event: Event) {
+ event.preventDefault();
+ await editor.autoIndent();
+ editor
+ .getCoreEditor()
+ .getContainer()
+ .focus();
+}
+
+export function getDocumentation(
+ editor: SenseEditor,
+ docLinkVersion: string
+): Promise {
+ return editor.getRequestsInRange().then(requests => {
+ if (!requests || requests.length === 0) {
+ return null;
+ }
+ const position = requests[0].range.end;
+ position.column = position.column - 1;
+ const endpoint = getEndpointFromPosition(editor, position, editor.parser);
+ if (endpoint && endpoint.documentation && endpoint.documentation.indexOf('http') !== -1) {
+ return endpoint.documentation
+ .replace('/master/', `/${docLinkVersion}/`)
+ .replace('/current/', `/${docLinkVersion}/`);
+ } else {
+ return null;
+ }
+ });
+}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/main/get_top_nav.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/main/get_top_nav.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/main/get_top_nav.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/main/get_top_nav.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/main/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/main/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/main/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/main/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/main/main.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/main/main.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/main/main.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/main/main.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/settings.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx
similarity index 98%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/settings.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx
index 8440faa6eeea8..795103a5c95bb 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/settings.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx
@@ -21,7 +21,7 @@ import React from 'react';
import { AutocompleteOptions, DevToolsSettingsModal } from '../components';
// @ts-ignore
-import mappings from '../../../../public/quarantined/src/mappings';
+import mappings from '../../lib/mappings/mappings';
import { useServicesContext, useEditorActionContext } from '../contexts';
import { DevToolsSettings } from '../../services';
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/create_use_context.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/create_use_context.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/create_use_context.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/create_use_context.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_context.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_context.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_context.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_registry.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts
similarity index 85%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_registry.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts
index bdccc1af0860c..64b0cddb4189b 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_registry.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts
@@ -17,15 +17,17 @@
* under the License.
*/
+import { SenseEditor } from '../../models/sense_editor';
+
export class EditorRegistry {
- inputEditor: any;
+ inputEditor: SenseEditor | undefined;
- setInputEditor(inputEditor: any) {
+ setInputEditor(inputEditor: SenseEditor) {
this.inputEditor = inputEditor;
}
getInputEditor() {
- return this.inputEditor;
+ return this.inputEditor!;
}
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/request_context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/contexts/request_context.tsx
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/request_context.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/request_context.tsx
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/services_context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx
similarity index 98%
rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/services_context.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx
index f715b1ae53a78..77f0924a51842 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/contexts/services_context.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx
@@ -28,6 +28,7 @@ interface ContextValue {
settings: Settings;
notifications: NotificationsSetup;
};
+ elasticsearchUrl: string;
docLinkVersion: string;
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/factories/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/factories/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/factories/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/factories/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/factories/token_iterator.ts b/src/legacy/core_plugins/console/public/np_ready/application/factories/token_iterator.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/factories/token_iterator.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/factories/token_iterator.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts
similarity index 59%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts
index b053e605b5fae..24af2df69809f 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts
@@ -17,26 +17,29 @@
* under the License.
*/
+import RowParser from '../../../lib/row_parser';
+import { SenseEditor } from '../../models/sense_editor';
/**
* This function is considered legacy and should not be changed or updated before we have editor
* interfaces in place (it's using a customized version of Ace directly).
*/
-export function restoreRequestFromHistory(input: any, req: any) {
- const session = input.getSession();
- let pos = input.getCursorPosition();
+export function restoreRequestFromHistory(editor: SenseEditor, req: any) {
+ const coreEditor = editor.getCoreEditor();
+ let pos = coreEditor.getCurrentPosition();
let prefix = '';
let suffix = '\n';
- if (input.parser.isStartRequestRow(pos.row)) {
- pos.column = 0;
+ const parser = new RowParser(coreEditor);
+ if (parser.isStartRequestRow(pos.lineNumber)) {
+ pos.column = 1;
suffix += '\n';
- } else if (input.parser.isEndRequestRow(pos.row)) {
- const line = session.getLine(pos.row);
- pos.column = line.length;
+ } else if (parser.isEndRequestRow(pos.lineNumber)) {
+ const line = coreEditor.getLineValue(pos.lineNumber);
+ pos.column = line.length + 1;
prefix = '\n\n';
- } else if (input.parser.isInBetweenRequestsRow(pos.row)) {
- pos.column = 0;
+ } else if (parser.isInBetweenRequestsRow(pos.lineNumber)) {
+ pos.column = 1;
} else {
- pos = input.nextRequestEnd(pos);
+ pos = editor.nextRequestEnd(pos);
prefix = '\n\n';
}
@@ -47,8 +50,8 @@ export function restoreRequestFromHistory(input: any, req: any) {
s += suffix;
- session.insert(pos, s);
- input.clearSelection();
- input.moveCursorTo(pos.row + prefix.length, 0);
- input.focus();
+ coreEditor.insert(pos, s);
+ coreEditor.moveCursorToPosition({ lineNumber: pos.lineNumber + prefix.length, column: 1 });
+ coreEditor.clearSelection();
+ coreEditor.getContainer().focus();
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
similarity index 96%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
index 22fa4477e9012..11c1f6638e9cf 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
@@ -17,10 +17,9 @@
* under the License.
*/
+import * as utils from '../../../lib/utils/utils';
// @ts-ignore
-import utils from '../../../../../public/quarantined/src/utils';
-// @ts-ignore
-import * as es from '../../../../../public/quarantined/src/es';
+import * as es from '../../../lib/es/es';
import { BaseResponseType } from '../../../types/common';
export interface EsRequestArgs {
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts
similarity index 94%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts
index 52661103b2d13..b51c29f8e9db6 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts
@@ -23,7 +23,7 @@ import { useServicesContext } from '../../contexts';
import { sendRequestToES } from './send_request_to_es';
import { useRequestActionContext } from '../../contexts';
// @ts-ignore
-import mappings from '../../../../../public/quarantined/src/mappings';
+import mappings from '../../../lib/mappings/mappings';
export const useSendCurrentRequestToES = () => {
const {
@@ -36,7 +36,7 @@ export const useSendCurrentRequestToES = () => {
dispatch({ type: 'sendRequest', payload: undefined });
try {
const editor = registry.getInputEditor();
- const requests = await new Promise(resolve => editor.getRequestsInRange(resolve));
+ const requests = await editor.getRequestsInRange();
if (!requests.length) {
dispatch({
type: 'requestFail',
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_set_input_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_set_input_editor.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/index.tsx b/src/legacy/core_plugins/console/public/np_ready/application/index.tsx
similarity index 91%
rename from src/legacy/core_plugins/console/np_ready/public/application/index.tsx
rename to src/legacy/core_plugins/console/public/np_ready/application/index.tsx
index e181caf23d2cb..239e4320f00f8 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/index.tsx
+++ b/src/legacy/core_plugins/console/public/np_ready/application/index.tsx
@@ -18,7 +18,7 @@
*/
import React from 'react';
-import { NotificationsSetup } from 'src/core/public';
+import { NotificationsSetup } from 'kibana/public';
import { ServicesContextProvider, EditorContextProvider, RequestContextProvider } from './contexts';
import { Main } from './containers';
import { createStorage, createHistory, createSettings, Settings } from '../services';
@@ -32,8 +32,9 @@ export function boot(deps: {
docLinkVersion: string;
I18nContext: any;
notifications: NotificationsSetup;
+ elasticsearchUrl: string;
}) {
- const { I18nContext, notifications, docLinkVersion } = deps;
+ const { I18nContext, notifications, docLinkVersion, elasticsearchUrl } = deps;
const storage = createStorage({
engine: window.localStorage,
@@ -47,6 +48,7 @@ export function boot(deps: {
indexPatternTypes.push(type);
+export * from './legacy_core_editor/legacy_core_editor';
+export * from './sense_editor';
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/input_tokenization.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/input_tokenization.test.js
similarity index 86%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/input_tokenization.test.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/input_tokenization.test.js
index 01f30f826ab26..febf472091e37 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/input_tokenization.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/input_tokenization.test.js
@@ -16,17 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-
-import './setup_mocks';
-import ace from 'brace';
-import 'brace/mode/json';
+import '../legacy_core_editor.test.mocks';
+import RowParser from '../../../../lib/row_parser';
+import { createTokenIterator } from '../../../factories';
import $ from 'jquery';
-import { initializeEditor } from '../../src/input';
-
-const tokenIterator = ace.acequire('ace/token_iterator');
+import { create } from '../create';
describe('Input Tokenization', () => {
- let input;
+ let coreEditor;
beforeEach(() => {
// Set up our document body
document.body.innerHTML =
@@ -36,33 +33,25 @@ describe('Input Tokenization', () => {
`;
- input = initializeEditor(
- $('#ConAppEditor'),
- $('#ConAppEditorActions'),
- );
-
- input = initializeEditor(
- $('#ConAppEditor'),
- $('#ConAppEditorActions'),
- );
- input.$el.show();
- input.autocomplete._test.removeChangeListener();
+ coreEditor = create(document.querySelector('#ConAppEditor'));
+
+ $(coreEditor.getContainer()).show();
});
afterEach(() => {
- input.$el.hide();
- input.autocomplete._test.addChangeListener();
+ $(coreEditor.getContainer()).hide();
});
function tokensAsList() {
- const iter = new tokenIterator.TokenIterator(input.getSession(), 0, 0);
+ const iter = createTokenIterator({ editor: coreEditor, position: { lineNumber: 1, column: 1 } });
const ret = [];
let t = iter.getCurrentToken();
- if (input.parser.isEmptyToken(t)) {
- t = input.parser.nextNonEmptyToken(iter);
+ const parser = new RowParser(coreEditor);
+ if (parser.isEmptyToken(t)) {
+ t = parser.nextNonEmptyToken(iter);
}
while (t) {
ret.push({ value: t.value, type: t.type });
- t = input.parser.nextNonEmptyToken(iter);
+ t = parser.nextNonEmptyToken(iter);
}
return ret;
@@ -83,18 +72,15 @@ describe('Input Tokenization', () => {
data = prefix;
}
- test('Token test ' + testCount++ + ' prefix: ' + prefix, async function (done) {
- input.update(data, function () {
- const tokens = tokensAsList();
- const normTokenList = [];
- for (let i = 0; i < tokenList.length; i++) {
- normTokenList.push({ type: tokenList[i++], value: tokenList[i] });
- }
-
- expect(tokens).toEqual(normTokenList);
- done();
- });
+ test('Token test ' + testCount++ + ' prefix: ' + prefix, async function () {
+ await coreEditor.setValue(data, true);
+ const tokens = tokensAsList();
+ const normTokenList = [];
+ for (let i = 0; i < tokenList.length; i++) {
+ normTokenList.push({ type: tokenList[i++], value: tokenList[i] });
+ }
+ expect(tokens).toEqual(normTokenList);
});
}
@@ -271,10 +257,8 @@ describe('Input Tokenization', () => {
function statesAsList() {
const ret = [];
- const session = input.getSession();
- const maxLine = session.getLength();
- for (let row = 0; row < maxLine; row++) ret.push(session.getState(row));
-
+ const maxLine = coreEditor.getLineCount();
+ for (let line = 1; line <= maxLine; line++) ret.push(coreEditor.getLineState(line));
return ret;
}
@@ -292,12 +276,10 @@ describe('Input Tokenization', () => {
data = prefix;
}
- test('States test ' + testCount++ + ' prefix: ' + prefix, async function (done) {
- input.update(data, function () {
- const modes = statesAsList();
- expect(modes).toEqual(statesList);
- done();
- });
+ test('States test ' + testCount++ + ' prefix: ' + prefix, async function () {
+ await coreEditor.setValue(data, true);
+ const modes = statesAsList();
+ expect(modes).toEqual(statesList);
});
}
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/output_tokenization.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js
similarity index 89%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/output_tokenization.test.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js
index 36c081f5ef923..b860f691dadb2 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/output_tokenization.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js
@@ -16,26 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-import './setup_mocks';
-import ace from 'brace';
-import 'brace/mode/javascript';
-import 'brace/mode/json';
-
const $ = require('jquery');
-const RowParser = require('../../src/sense_editor/row_parser');
-
-import { initializeOutput } from '../../src/output';
+import RowParser from '../../../../lib/row_parser';
+import ace from 'brace';
+import { createReadOnlyAceEditor } from '../create_readonly';
let output;
-
const tokenIterator = ace.acequire('ace/token_iterator');
describe('Output Tokenization', () => {
beforeEach(() => {
- output = initializeOutput($('#ConAppOutput'));
- output.$el.show();
+ output = createReadOnlyAceEditor(document.querySelector('#ConAppOutput'));
+ $(output.container).show();
});
+
afterEach(() => {
- output.$el.hide();
+ $(output.container).hide();
});
function tokensAsList() {
diff --git a/src/legacy/ui/public/management/index_pattern_creation/register.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts
similarity index 67%
rename from src/legacy/ui/public/management/index_pattern_creation/register.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts
index bca4387b496fd..8e03182621c83 100644
--- a/src/legacy/ui/public/management/index_pattern_creation/register.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts
@@ -17,7 +17,14 @@
* under the License.
*/
-import { IndexPatternCreationConfig } from './index_pattern_creation_config';
-import { addIndexPatternType } from './index_pattern_types';
+import ace from 'brace';
+import { LegacyCoreEditor } from './legacy_core_editor';
-addIndexPatternType(IndexPatternCreationConfig);
+export const create = (el: HTMLElement) => {
+ const actions = document.querySelector('#ConAppEditorActions');
+ if (!actions) {
+ throw new Error('Could not find ConAppEditorActions element!');
+ }
+ const aceEditor = ace.edit(el);
+ return new LegacyCoreEditor(aceEditor, actions);
+};
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/output.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts
similarity index 70%
rename from src/legacy/core_plugins/console/public/quarantined/src/output.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts
index 42555f17f19c1..ce8ededd0b12c 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/output.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts
@@ -18,19 +18,28 @@
*/
import _ from 'lodash';
-const ace = require('brace');
-const OutputMode = require('./sense_editor/mode/output');
-const smartResize = require('./smart_resize');
+import ace from 'brace';
+// @ts-ignore
+import * as OutputMode from './mode/output';
+import smartResize from './smart_resize';
-let output;
-export function initializeOutput($el) {
- output = ace.acequire('ace/ace').edit($el[0]);
+export interface CustomAceEditor extends ace.Editor {
+ update: (text: string, mode?: any, cb?: () => void) => void;
+ append: (text: string, foldPrevious?: boolean, cb?: () => void) => void;
+}
+
+/**
+ * Note: using read-only ace editor leaks the Ace editor API - use this as sparingly as possible or
+ * create an interface for it so that we don't rely directly on vendor APIs.
+ */
+export function createReadOnlyAceEditor(element: HTMLElement): CustomAceEditor {
+ const output: CustomAceEditor = ace.acequire('ace/ace').edit(element);
const outputMode = new OutputMode.Mode();
output.$blockScrolling = Infinity;
output.resize = smartResize(output);
- output.update = (val, mode, cb) => {
+ output.update = (val: string, mode?: any, cb?: () => void) => {
if (typeof mode === 'function') {
cb = mode;
mode = void 0;
@@ -45,7 +54,7 @@ export function initializeOutput($el) {
}
};
- output.append = (val, foldPrevious, cb) => {
+ output.append = (val: string, foldPrevious?: boolean, cb?: () => void) => {
if (typeof foldPrevious === 'function') {
cb = foldPrevious;
foldPrevious = true;
@@ -65,12 +74,10 @@ export function initializeOutput($el) {
}
};
- output.$el = $el;
-
// eslint-disable-next-line
(function setupSession(session) {
session.setMode('ace/mode/text');
- session.setFoldStyle('markbeginend');
+ (session as any).setFoldStyle('markbeginend');
session.setTabSize(2);
session.setUseWrapMode(true);
})(output.getSession());
@@ -80,7 +87,3 @@ export function initializeOutput($el) {
return output;
}
-
-export default function getOutput() {
- return output;
-}
diff --git a/src/legacy/ui/public/management/index_pattern_list/register.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts
similarity index 77%
rename from src/legacy/ui/public/management/index_pattern_list/register.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts
index 6488ddd399b7b..7655bbcd106d2 100644
--- a/src/legacy/ui/public/management/index_pattern_list/register.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts
@@ -17,7 +17,12 @@
* under the License.
*/
-import { IndexPatternListConfig } from './index_pattern_list_config';
-import { IndexPatternListConfigRegistry } from './index_pattern_list_config_registry';
+import 'brace';
+import 'brace/ext/language_tools';
+import 'brace/ext/searchbox';
+import 'brace/mode/json';
+import 'brace/mode/text';
-IndexPatternListConfigRegistry.register(() => IndexPatternListConfig);
+export * from './legacy_core_editor';
+export * from './create_readonly';
+export * from './create';
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/setup_mocks.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts
similarity index 69%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/setup_mocks.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts
index 203d8a20b1055..66673ff42e4e8 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/setup_mocks.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts
@@ -16,23 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
-/* eslint no-undef: 0 */
-jest.mock('../../src/sense_editor/mode/worker', () => {
- return { workerModule: { id: 'sense_editor/mode/worker', src: '' } };
-});
-jest.mock('ui/chrome', () => {
- return {
- getInjected() {
- return 'http://localhost:9200';
- }
- };
+jest.mock('./mode/worker', () => {
+ return { workerModule: { id: 'sense_editor/mode/worker', src: '' } };
});
-window.Worker = function () {
+// @ts-ignore
+window.Worker = function() {
this.postMessage = () => {};
- this.terminate = () => {};
+ (this as any).terminate = () => {};
};
+
+// @ts-ignore
window.URL = {
createObjectURL: () => {
return '';
@@ -45,14 +40,4 @@ import 'brace/ext/searchbox';
import 'brace/mode/json';
import 'brace/mode/text';
-jest.mock('../../../../np_ready/public/application', () => ({ legacyBackDoorToSettings: () => {}, }));
-
document.queryCommandSupported = () => true;
-
-import jQuery from 'jquery';
-jest.spyOn(jQuery, 'ajax').mockImplementation(
- () =>
- new Promise(() => {
- // never resolve
- })
-);
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts
new file mode 100644
index 0000000000000..621f4eeb0163e
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts
@@ -0,0 +1,340 @@
+/*
+ * 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 ace from 'brace';
+import { Editor as IAceEditor } from 'brace';
+import $ from 'jquery';
+import { CoreEditor, Position, Range, Token, TokensProvider, EditorEvent } from '../../../types';
+import { AceTokensProvider } from '../../../lib/ace_token_provider';
+import * as curl from '../sense_editor/curl';
+import smartResize from './smart_resize';
+
+// @ts-ignore
+import * as InputMode from './mode/input';
+
+const _AceRange = ace.acequire('ace/range').Range;
+
+const rangeToAceRange = ({ start, end }: Range) =>
+ new _AceRange(start.lineNumber - 1, start.column - 1, end.lineNumber - 1, end.column - 1);
+
+export class LegacyCoreEditor implements CoreEditor {
+ private _aceOnPaste: any;
+ $actions: any;
+ resize: () => void;
+
+ constructor(private readonly editor: IAceEditor, actions: HTMLElement) {
+ this.$actions = $(actions);
+ this.editor.setShowPrintMargin(false);
+
+ const session = this.editor.getSession();
+ session.setMode(new InputMode.Mode());
+ (session as any).setFoldStyle('markbeginend');
+ session.setTabSize(2);
+ session.setUseWrapMode(true);
+
+ this.resize = smartResize(this.editor);
+
+ // Intercept ace on paste handler.
+ this._aceOnPaste = this.editor.onPaste;
+ this.editor.onPaste = this.DO_NOT_USE_onPaste.bind(this);
+
+ this.editor.setOptions({
+ enableBasicAutocompletion: true,
+ });
+
+ this.editor.$blockScrolling = Infinity;
+ this.hideActionsBar();
+ this.editor.focus();
+ }
+
+ // dirty check for tokenizer state, uses a lot less cycles
+ // than listening for tokenizerUpdate
+ waitForLatestTokens(): Promise {
+ return new Promise(resolve => {
+ const session = this.editor.getSession();
+ const checkInterval = 25;
+
+ const check = () => {
+ // If the bgTokenizer doesn't exist, we can assume that the underlying editor has been
+ // torn down, e.g. by closing the History tab, and we don't need to do anything further.
+ if (session.bgTokenizer) {
+ // Wait until the bgTokenizer is done running before executing the callback.
+ if ((session.bgTokenizer as any).running) {
+ setTimeout(check, checkInterval);
+ } else {
+ resolve();
+ }
+ }
+ };
+
+ setTimeout(check, 0);
+ });
+ }
+
+ getLineState(lineNumber: number) {
+ const session = this.editor.getSession();
+ return session.getState(lineNumber - 1);
+ }
+
+ getValueInRange(range: Range): string {
+ return this.editor.getSession().getTextRange(rangeToAceRange(range));
+ }
+
+ getTokenProvider(): TokensProvider {
+ return new AceTokensProvider(this.editor.getSession());
+ }
+
+ getValue(): string {
+ return this.editor.getValue();
+ }
+
+ setValue(text: string, forceRetokenize: boolean): Promise {
+ const session = this.editor.getSession();
+ session.setValue(text);
+ return new Promise(resolve => {
+ if (!forceRetokenize) {
+ // resolve immediately
+ resolve();
+ return;
+ }
+
+ // force update of tokens, but not on this thread to allow for ace rendering.
+ setTimeout(function() {
+ let i;
+ for (i = 0; i < session.getLength(); i++) {
+ session.getTokens(i);
+ }
+ resolve();
+ });
+ });
+ }
+
+ getLineValue(lineNumber: number): string {
+ const session = this.editor.getSession();
+ return session.getLine(lineNumber - 1);
+ }
+
+ getCurrentPosition(): Position {
+ const cursorPosition = this.editor.getCursorPosition();
+ return {
+ lineNumber: cursorPosition.row + 1,
+ column: cursorPosition.column + 1,
+ };
+ }
+
+ clearSelection(): void {
+ this.editor.clearSelection();
+ }
+
+ getTokenAt(pos: Position): Token | null {
+ const provider = this.getTokenProvider();
+ return provider.getTokenAt(pos);
+ }
+
+ insert(valueOrPos: string | Position, value?: string): void {
+ if (typeof valueOrPos === 'string') {
+ this.editor.insert(valueOrPos);
+ return;
+ }
+ const document = this.editor.getSession().getDocument();
+ document.insert(
+ {
+ column: valueOrPos.column - 1,
+ row: valueOrPos.lineNumber - 1,
+ },
+ value || ''
+ );
+ }
+
+ moveCursorToPosition(pos: Position): void {
+ this.editor.moveCursorToPosition({ row: pos.lineNumber - 1, column: pos.column - 1 });
+ }
+
+ replace(range: Range, value: string): void {
+ const session = this.editor.getSession();
+ session.replace(rangeToAceRange(range), value);
+ }
+
+ getLines(startLine: number, endLine: number): string[] {
+ const session = this.editor.getSession();
+ return session.getLines(startLine - 1, endLine - 1);
+ }
+
+ replaceRange(range: Range, value: string) {
+ const pos = this.editor.getCursorPosition();
+ this.editor.getSession().replace(rangeToAceRange(range), value);
+
+ const maxRow = Math.max(range.start.lineNumber - 1 + value.split('\n').length - 1, 1);
+ pos.row = Math.min(pos.row, maxRow);
+ this.editor.moveCursorToPosition(pos);
+ // ACE UPGRADE - check if needed - at the moment the above may trigger a selection.
+ this.editor.clearSelection();
+ }
+
+ getSelectionRange() {
+ const result = this.editor.getSelectionRange();
+ return {
+ start: {
+ lineNumber: result.start.row + 1,
+ column: result.start.column + 1,
+ },
+ end: {
+ lineNumber: result.end.row + 1,
+ column: result.end.column + 1,
+ },
+ };
+ }
+
+ getLineCount() {
+ const text = this.getValue();
+ return text.split('\n').length;
+ }
+
+ addMarker(range: Range) {
+ return this.editor
+ .getSession()
+ .addMarker(rangeToAceRange(range), 'ace_snippet-marker', 'fullLine', false);
+ }
+
+ removeMarker(ref: any) {
+ this.editor.getSession().removeMarker(ref);
+ }
+
+ getWrapLimit(): number {
+ return this.editor.getSession().getWrapLimit();
+ }
+
+ on(event: EditorEvent, listener: () => void) {
+ if (event === 'changeCursor') {
+ this.editor.getSession().selection.on(event, listener);
+ } else if (event === 'changeSelection') {
+ this.editor.on(event, listener);
+ } else {
+ this.editor.getSession().on(event, listener);
+ }
+ }
+
+ off(event: EditorEvent, listener: () => void) {
+ if (event === 'changeSelection') {
+ this.editor.off(event, listener);
+ }
+ }
+
+ isCompleterActive() {
+ // Secrets of the arcane here.
+ return Boolean((this.editor as any).completer && (this.editor as any).completer.activated);
+ }
+
+ // eslint-disable-next-line @typescript-eslint/camelcase
+ private DO_NOT_USE_onPaste(text: string) {
+ if (text && curl.detectCURL(text)) {
+ const curlInput = curl.parseCURL(text);
+ this.editor.insert(curlInput);
+ return;
+ }
+ this._aceOnPaste.call(this.editor, text);
+ }
+
+ private setActionsBar = (top?: any) => {
+ if (top === null) {
+ this.$actions.css('visibility', 'hidden');
+ } else {
+ this.$actions.css({
+ top,
+ visibility: 'visible',
+ });
+ }
+ };
+
+ private hideActionsBar = () => {
+ this.setActionsBar();
+ };
+
+ execCommand(cmd: string) {
+ this.editor.execCommand(cmd);
+ }
+
+ getContainer(): HTMLDivElement {
+ return this.editor.container as HTMLDivElement;
+ }
+
+ setStyles(styles: { wrapLines: boolean; fontSize: string }) {
+ this.editor.getSession().setUseWrapMode(styles.wrapLines);
+ this.editor.container.style.fontSize = styles.fontSize;
+ }
+
+ registerKeyboardShortcut(opts: { keys: string; fn: () => void; name: string }): void {
+ this.editor.commands.addCommand({
+ exec: opts.fn,
+ name: opts.name,
+ bindKey: opts.keys,
+ });
+ }
+
+ legacyUpdateUI(range: any) {
+ if (!this.$actions) {
+ return;
+ }
+ if (range) {
+ // elements are positioned relative to the editor's container
+ // pageY is relative to page, so subtract the offset
+ // from pageY to get the new top value
+ const offsetFromPage = $(this.editor.container).offset()!.top;
+ const startRow = range.start.lineNumber - 1;
+ const startColumn = range.start.column;
+ const firstLine = this.getLineValue(startRow);
+ const maxLineLength = this.getWrapLimit() - 5;
+ const isWrapping = firstLine.length > maxLineLength;
+ const getScreenCoords = (row: number) =>
+ this.editor.renderer.textToScreenCoordinates(row, startColumn).pageY - offsetFromPage;
+ const topOfReq = getScreenCoords(startRow);
+
+ if (topOfReq >= 0) {
+ let offset = 0;
+ if (isWrapping) {
+ // Try get the line height of the text area in pixels.
+ const textArea = $(this.editor.container.querySelector('textArea')!);
+ const hasRoomOnNextLine = this.getLineValue(startRow + 1).length < maxLineLength;
+ if (textArea && hasRoomOnNextLine) {
+ // Line height + the number of wraps we have on a line.
+ offset += this.getLineValue(startRow).length * textArea.height()!;
+ } else {
+ if (startRow > 0) {
+ this.setActionsBar(getScreenCoords(startRow - 1));
+ return;
+ }
+ this.setActionsBar(getScreenCoords(startRow + 1));
+ return;
+ }
+ }
+ this.setActionsBar(topOfReq + offset);
+ return;
+ }
+
+ const bottomOfReq =
+ this.editor.renderer.textToScreenCoordinates(range.end.lineNumber, range.end.column).pageY -
+ offsetFromPage;
+
+ if (bottomOfReq >= 0) {
+ this.setActionsBar(0);
+ return;
+ }
+ }
+ }
+}
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input_highlight_rules.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input_highlight_rules.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input_highlight_rules.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output_highlight_rules.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output_highlight_rules.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output_highlight_rules.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script_highlight_rules.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script_highlight_rules.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script_highlight_rules.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/index.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/index.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/index.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/index.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/worker.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/worker.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/worker.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/worker.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/x_json_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/x_json_highlight_rules.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/x_json_highlight_rules.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/x_json_highlight_rules.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/smart_resize.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts
similarity index 92%
rename from src/legacy/core_plugins/console/public/quarantined/src/smart_resize.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts
index 8ac5eda345c23..b88e0e44591d8 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/smart_resize.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts
@@ -19,7 +19,8 @@
import { get, throttle } from 'lodash';
-export default function (editor) {
+// eslint-disable-next-line import/no-default-export
+export default function(editor: any) {
const resize = editor.resize;
const throttledResize = throttle(() => {
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/theme_sense_dark.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/theme_sense_dark.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/theme_sense_dark.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/theme_sense_dark.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/editor_input1.txt b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/editor_input1.txt
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/editor_input1.txt
rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/editor_input1.txt
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/integration.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js
similarity index 80%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/integration.test.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js
index 9df4aa5e0bece..0950992f1c0fe 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/integration.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js
@@ -16,51 +16,44 @@
* specific language governing permissions and limitations
* under the License.
*/
-import './setup_mocks';
-import 'brace';
-import 'brace/mode/json';
-import { initializeEditor } from '../../src/input';
+import '../sense_editor.test.mocks';
+import { create } from '../create';
import _ from 'lodash';
const $ = require('jquery');
-const kb = require('../../src/kb');
-const mappings = require('../../src/mappings');
-
-
+const kb = require('../../../../lib/kb/kb');
+const mappings = require('../../../../lib/mappings/mappings');
describe('Integration', () => {
- let input;
+ let senseEditor;
beforeEach(() => {
// Set up our document body
document.body.innerHTML =
'';
- input = initializeEditor(
- $('#ConAppEditor'),
- $('#ConAppEditorActions')
- );
- input.$el.show();
- input.autocomplete._test.removeChangeListener();
+ senseEditor = create(document.querySelector('#ConAppEditor'));
+ $(senseEditor.getCoreEditor().getContainer()).show();
+ senseEditor.autocomplete._test.removeChangeListener();
});
afterEach(() => {
- input.$el.hide();
- input.autocomplete._test.addChangeListener();
+ $(senseEditor.getCoreEditor().getContainer()).hide();
+ senseEditor.autocomplete._test.addChangeListener();
});
function processContextTest(data, mapping, kbSchemes, requestLine, testToRun) {
test(testToRun.name, async function (done) {
- let rowOffset = 0; // add one for the extra method line
+ let lineOffset = 0; // add one for the extra method line
let editorValue = data;
if (requestLine != null) {
if (data != null) {
editorValue = requestLine + '\n' + data;
- rowOffset = 1;
+ lineOffset = 1;
} else {
editorValue = requestLine;
}
}
- testToRun.cursor.row += rowOffset;
+ testToRun.cursor.lineNumber += lineOffset;
mappings.clear();
mappings.loadMappings(mapping);
@@ -81,109 +74,104 @@ describe('Integration', () => {
}
kb.setActiveApi(testApi);
const { cursor } = testToRun;
- const { row, column } = cursor;
- input.update(editorValue, function () {
- input.moveCursorTo(row, column);
+ await senseEditor.update(editorValue, true);
+ senseEditor.getCoreEditor().moveCursorToPosition(cursor);
- // allow ace rendering to move cursor so it will be seen during test - handy for debugging.
- //setTimeout(function () {
- input.completer = {
- base: {},
- changeListener: function () {},
- }; // mimic auto complete
+ // allow ace rendering to move cursor so it will be seen during test - handy for debugging.
+ //setTimeout(function () {
+ senseEditor.completer = {
+ base: {},
+ changeListener: function () {},
+ }; // mimic auto complete
- input.autocomplete._test.getCompletions(
- input,
- input.getSession(),
- cursor,
- '',
- function (err, terms) {
- if (testToRun.assertThrows) {
- done();
- return;
- }
+ senseEditor.autocomplete._test.getCompletions(
+ senseEditor,
+ null,
+ { row: cursor.lineNumber - 1, column: cursor.column - 1 },
+ '',
+ function (err, terms) {
+ if (testToRun.assertThrows) {
+ done();
+ return;
+ }
- if (err) {
- done();
- throw err;
- }
+ if (err) {
+ throw err;
+ }
- if (testToRun.no_context) {
- expect(!terms || terms.length === 0).toBeTruthy();
- } else {
- expect(terms).not.toBeNull();
- expect(terms.length).toBeGreaterThan(0);
- }
+ if (testToRun.no_context) {
+ expect(!terms || terms.length === 0).toBeTruthy();
+ } else {
+ expect(terms).not.toBeNull();
+ expect(terms.length).toBeGreaterThan(0);
+ }
- if (!terms || terms.length === 0) {
- done();
- return;
- }
+ if (!terms || terms.length === 0) {
+ done();
+ return;
+ }
- if (testToRun.autoCompleteSet) {
- const expectedTerms = _.map(testToRun.autoCompleteSet, function (t) {
- if (typeof t !== 'object') {
- t = { name: t };
- }
- return t;
- });
- if (terms.length !== expectedTerms.length) {
- expect(_.pluck(terms, 'name')).toEqual(_.pluck(expectedTerms, 'name'));
- } else {
- const filteredActualTerms = _.map(terms, function (
- actualTerm,
- i
- ) {
- const expectedTerm = expectedTerms[i];
- const filteredTerm = {};
- _.each(expectedTerm, function (v, p) {
- filteredTerm[p] = actualTerm[p];
- });
- return filteredTerm;
- });
- expect(filteredActualTerms).toEqual(expectedTerms);
+ if (testToRun.autoCompleteSet) {
+ const expectedTerms = _.map(testToRun.autoCompleteSet, function (t) {
+ if (typeof t !== 'object') {
+ t = { name: t };
}
- done();
+ return t;
+ });
+ if (terms.length !== expectedTerms.length) {
+ expect(_.pluck(terms, 'name')).toEqual(_.pluck(expectedTerms, 'name'));
+ } else {
+ const filteredActualTerms = _.map(terms, function (
+ actualTerm,
+ i
+ ) {
+ const expectedTerm = expectedTerms[i];
+ const filteredTerm = {};
+ _.each(expectedTerm, function (v, p) {
+ filteredTerm[p] = actualTerm[p];
+ });
+ return filteredTerm;
+ });
+ expect(filteredActualTerms).toEqual(expectedTerms);
}
+ }
- const context = terms[0].context;
- const { cursor: { row, column } } = testToRun;
- input.autocomplete._test.addReplacementInfoToContext(
- context,
- { lineNumber: row + 1, column: column + 1 },
- terms[0].value
- );
+ const context = terms[0].context;
+ const { cursor: { lineNumber, column } } = testToRun;
+ senseEditor.autocomplete._test.addReplacementInfoToContext(
+ context,
+ { lineNumber, column },
+ terms[0].value
+ );
- function ac(prop, propTest) {
- if (typeof testToRun[prop] !== 'undefined') {
- if (propTest) {
- propTest(context[prop], testToRun[prop], prop);
- } else {
- expect(context[prop]).toEqual(testToRun[prop]);
- }
+ function ac(prop, propTest) {
+ if (typeof testToRun[prop] !== 'undefined') {
+ if (propTest) {
+ propTest(context[prop], testToRun[prop], prop);
+ } else {
+ expect(context[prop]).toEqual(testToRun[prop]);
}
}
+ }
- function posCompare(actual, expected) {
- expect(actual.lineNumber).toEqual(expected.lineNumber + rowOffset);
- expect(actual.column).toEqual(expected.column);
- }
-
- function rangeCompare(actual, expected, name) {
- posCompare(actual.start, expected.start, name + '.start');
- posCompare(actual.end, expected.end, name + '.end');
- }
+ function posCompare(actual, expected) {
+ expect(actual.lineNumber).toEqual(expected.lineNumber + lineOffset);
+ expect(actual.column).toEqual(expected.column);
+ }
- ac('prefixToAdd');
- ac('suffixToAdd');
- ac('addTemplate');
- ac('textBoxPosition', posCompare);
- ac('rangeToReplace', rangeCompare);
- done();
+ function rangeCompare(actual, expected, name) {
+ posCompare(actual.start, expected.start, name + '.start');
+ posCompare(actual.end, expected.end, name + '.end');
}
- );
- //});
- });
+
+ ac('prefixToAdd');
+ ac('suffixToAdd');
+ ac('addTemplate');
+ ac('textBoxPosition', posCompare);
+ ac('rangeToReplace', rangeCompare);
+ done();
+ }
+ );
});
}
@@ -236,7 +224,7 @@ describe('Integration', () => {
contextTests({}, MAPPING, SEARCH_KB, 'POST _search', [
{
name: 'Empty doc',
- cursor: { row: 0, column: 1 },
+ cursor: { lineNumber: 1, column: 2 },
initialValue: '',
addTemplate: true,
prefixToAdd: '',
@@ -252,7 +240,7 @@ describe('Integration', () => {
contextTests({}, MAPPING, SEARCH_KB, 'POST _no_context', [
{
name: 'Missing KB',
- cursor: { row: 0, column: 1 },
+ cursor: { lineNumber: 1, column: 2 },
no_context: true,
},
]);
@@ -276,7 +264,7 @@ describe('Integration', () => {
[
{
name: 'Missing KB - global auto complete',
- cursor: { row: 2, column: 5 },
+ cursor: { lineNumber: 3, column: 6 },
autoCompleteSet: ['t1'],
},
]
@@ -296,7 +284,7 @@ describe('Integration', () => {
[
{
name: 'existing dictionary key, no template',
- cursor: { row: 1, column: 6 },
+ cursor: { lineNumber: 2, column: 6 },
initialValue: 'query',
addTemplate: false,
prefixToAdd: '',
@@ -309,7 +297,7 @@ describe('Integration', () => {
},
{
name: 'existing inner dictionary key',
- cursor: { row: 2, column: 7 },
+ cursor: { lineNumber: 3, column: 8 },
initialValue: 'field',
addTemplate: false,
prefixToAdd: '',
@@ -322,7 +310,7 @@ describe('Integration', () => {
},
{
name: 'existing dictionary key, yes template',
- cursor: { row: 4, column: 7 },
+ cursor: { lineNumber: 5, column: 8 },
initialValue: 'facets',
addTemplate: true,
prefixToAdd: '',
@@ -335,13 +323,12 @@ describe('Integration', () => {
},
{
name: 'ignoring meta keys',
- cursor: { row: 4, column: 14 },
+ cursor: { lineNumber: 5, column: 15 },
no_context: true,
},
]
);
-
contextTests(
'{\n' +
' "query": {\n' +
@@ -356,7 +343,7 @@ describe('Integration', () => {
[
{
name: 'trailing comma, end of line',
- cursor: { row: 4, column: 16 },
+ cursor: { lineNumber: 5, column: 17 },
initialValue: '',
addTemplate: true,
prefixToAdd: '',
@@ -369,7 +356,7 @@ describe('Integration', () => {
},
{
name: 'trailing comma, beginning of line',
- cursor: { row: 5, column: 1 },
+ cursor: { lineNumber: 6, column: 2 },
initialValue: '',
addTemplate: true,
prefixToAdd: '',
@@ -382,7 +369,7 @@ describe('Integration', () => {
},
{
name: 'prefix comma, beginning of line',
- cursor: { row: 6, column: 0 },
+ cursor: { lineNumber: 7, column: 1 },
initialValue: '',
addTemplate: true,
prefixToAdd: ', ',
@@ -395,7 +382,7 @@ describe('Integration', () => {
},
{
name: 'prefix comma, end of line',
- cursor: { row: 5, column: 14 },
+ cursor: { lineNumber: 6, column: 15 },
initialValue: '',
addTemplate: true,
prefixToAdd: ', ',
@@ -437,31 +424,31 @@ describe('Integration', () => {
[
{
name: 'not matching object when { is not opened',
- cursor: { row: 1, column: 12 },
+ cursor: { lineNumber: 2, column: 13 },
initialValue: '',
autoCompleteSet: ['{'],
},
{
name: 'not matching array when [ is not opened',
- cursor: { row: 2, column: 12 },
+ cursor: { lineNumber: 3, column: 13 },
initialValue: '',
autoCompleteSet: ['['],
},
{
name: 'matching value with one_of',
- cursor: { row: 3, column: 19 },
+ cursor: { lineNumber: 4, column: 20 },
initialValue: '',
autoCompleteSet: [1, 2],
},
{
name: 'matching value',
- cursor: { row: 4, column: 12 },
+ cursor: { lineNumber: 5, column: 13 },
initialValue: '',
autoCompleteSet: [3],
},
{
name: 'matching any value with one_of',
- cursor: { row: 5, column: 21 },
+ cursor: { lineNumber: 6, column: 22 },
initialValue: '',
autoCompleteSet: [4, 5],
},
@@ -484,7 +471,7 @@ describe('Integration', () => {
[
{
name: '* matching everything',
- cursor: { row: 5, column: 15 },
+ cursor: { lineNumber: 6, column: 16 },
initialValue: '',
addTemplate: true,
prefixToAdd: '',
@@ -517,7 +504,7 @@ describe('Integration', () => {
[
{
name: '{index} matching',
- cursor: { row: 1, column: 15 },
+ cursor: { lineNumber: 2, column: 16 },
autoCompleteSet: [
{ name: 'index1', meta: 'index' },
{ name: 'index2', meta: 'index' },
@@ -558,7 +545,7 @@ describe('Integration', () => {
[
{
name: 'Templates 1',
- cursor: { row: 1, column: 0 },
+ cursor: { lineNumber: 2, column: 1 },
autoCompleteSet: [
tt('array', []),
tt('fixed', { a: 1 }),
@@ -569,7 +556,7 @@ describe('Integration', () => {
},
{
name: 'Templates - one off',
- cursor: { row: 4, column: 12 },
+ cursor: { lineNumber: 5, column: 13 },
autoCompleteSet: [tt('o1'), tt('o2')],
},
]
@@ -612,7 +599,7 @@ describe('Integration', () => {
[
{
name: 'Conditionals',
- cursor: { row: 2, column: 15 },
+ cursor: { lineNumber: 3, column: 16 },
autoCompleteSet: [tt('always', {}), tt('match', {})],
},
]
@@ -655,7 +642,7 @@ describe('Integration', () => {
[
{
name: 'Any of - templates',
- cursor: { row: 1, column: 0 },
+ cursor: { lineNumber: 2, column: 1 },
autoCompleteSet: [
tt('any_of_mixed', []),
tt('any_of_numbers', [1, 2]),
@@ -664,22 +651,22 @@ describe('Integration', () => {
},
{
name: 'Any of - numbers',
- cursor: { row: 2, column: 2 },
+ cursor: { lineNumber: 3, column: 3 },
autoCompleteSet: [1, 2, 3],
},
{
name: 'Any of - object',
- cursor: { row: 6, column: 2 },
+ cursor: { lineNumber: 7, column: 3 },
autoCompleteSet: [tt('a', 1), tt('b', 2), tt('c', 1)],
},
{
name: 'Any of - mixed - obj',
- cursor: { row: 11, column: 2 },
+ cursor: { lineNumber: 12, column: 3 },
autoCompleteSet: [tt('a', 1)],
},
{
name: 'Any of - mixed - both',
- cursor: { row: 13, column: 2 },
+ cursor: { lineNumber: 14, column: 3 },
autoCompleteSet: [tt('{'), tt(3)],
},
]
@@ -702,7 +689,7 @@ describe('Integration', () => {
[
{
name: 'Empty string as default',
- cursor: { row: 0, column: 1 },
+ cursor: { lineNumber: 1, column: 2 },
autoCompleteSet: [tt('query', '')],
},
]
@@ -785,7 +772,7 @@ describe('Integration', () => {
[
{
name: 'Relative scope link test',
- cursor: { row: 2, column: 12 },
+ cursor: { lineNumber: 3, column: 13 },
autoCompleteSet: [
tt('b', {}),
tt('c', {}),
@@ -798,37 +785,37 @@ describe('Integration', () => {
},
{
name: 'External scope link test',
- cursor: { row: 3, column: 12 },
+ cursor: { lineNumber: 4, column: 13 },
autoCompleteSet: [tt('t2', 1)],
},
{
name: 'Global scope link test',
- cursor: { row: 4, column: 12 },
+ cursor: { lineNumber: 5, column: 13 },
autoCompleteSet: [tt('t1', 2), tt('t1a', {})],
},
{
name: 'Global scope link with an internal scope link',
- cursor: { row: 5, column: 17 },
+ cursor: { lineNumber: 6, column: 18 },
autoCompleteSet: [tt('t1', 2), tt('t1a', {})],
},
{
name: 'Entire endpoint scope link test',
- cursor: { row: 7, column: 12 },
+ cursor: { lineNumber: 8, column: 13 },
autoCompleteSet: [tt('target', {})],
},
{
name: 'A scope link within an array',
- cursor: { row: 9, column: 10 },
+ cursor: { lineNumber: 10, column: 11 },
autoCompleteSet: [tt('t2', 1)],
},
{
name: 'A function based scope link',
- cursor: { row: 11, column: 12 },
+ cursor: { lineNumber: 12, column: 13 },
autoCompleteSet: [tt('a', 1), tt('b', 2)],
},
{
name: 'A global scope link with wrong link',
- cursor: { row: 12, column: 12 },
+ cursor: { lineNumber: 13, column: 13 },
assertThrows: /broken/,
},
]
@@ -857,7 +844,7 @@ describe('Integration', () => {
[
{
name: 'Top level scope link',
- cursor: { row: 0, column: 1 },
+ cursor: { lineNumber: 1, column: 2 },
autoCompleteSet: [tt('t1', 2)],
},
]
@@ -883,7 +870,7 @@ describe('Integration', () => {
[
{
name: 'Path after empty object',
- cursor: { row: 1, column: 10 },
+ cursor: { lineNumber: 2, column: 11 },
autoCompleteSet: ['a', 'b'],
},
]
@@ -899,7 +886,7 @@ describe('Integration', () => {
[
{
name: 'Replace an empty string',
- cursor: { row: 1, column: 4 },
+ cursor: { lineNumber: 2, column: 5 },
rangeToReplace: {
start: { lineNumber: 2, column: 4 },
end: { lineNumber: 2, column: 10 },
@@ -931,12 +918,12 @@ describe('Integration', () => {
[
{
name: 'List of objects - internal autocomplete',
- cursor: { row: 3, column: 10 },
+ cursor: { lineNumber: 4, column: 11 },
autoCompleteSet: ['b'],
},
{
name: 'List of objects - external template',
- cursor: { row: 0, column: 1 },
+ cursor: { lineNumber: 1, column: 2 },
autoCompleteSet: [tt('a', [{}])],
},
]
@@ -964,7 +951,7 @@ describe('Integration', () => {
[
{
name: 'Field completion as scope',
- cursor: { row: 3, column: 10 },
+ cursor: { lineNumber: 4, column: 11 },
autoCompleteSet: [
tt('field1.1.1', { f: 1 }, 'string'),
tt('field1.1.2', { f: 1 }, 'string'),
@@ -972,7 +959,7 @@ describe('Integration', () => {
},
{
name: 'Field completion as value',
- cursor: { row: 9, column: 23 },
+ cursor: { lineNumber: 10, column: 24 },
autoCompleteSet: [
{ name: 'field1.1.1', meta: 'string' },
{ name: 'field1.1.2', meta: 'string' },
@@ -985,7 +972,7 @@ describe('Integration', () => {
contextTests('POST _search\n', MAPPING, SEARCH_KB, null, [
{
name: 'initial doc start',
- cursor: { row: 1, column: 0 },
+ cursor: { lineNumber: 2, column: 1 },
autoCompleteSet: ['{'],
prefixToAdd: '',
suffixToAdd: '',
@@ -1000,14 +987,14 @@ describe('Integration', () => {
[
{
name: 'Cursor rows after request end',
- cursor: { row: 4, column: 0 },
+ cursor: { lineNumber: 5, column: 1 },
autoCompleteSet: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'],
prefixToAdd: '',
suffixToAdd: ' ',
},
{
name: 'Cursor just after request end',
- cursor: { row: 2, column: 1 },
+ cursor: { lineNumber: 3, column: 2 },
no_context: true,
},
]
@@ -1041,7 +1028,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster', [
{
name: 'Endpoints with slashes - no slash',
- cursor: { row: 0, column: 8 },
+ cursor: { lineNumber: 1, column: 9 },
autoCompleteSet: [
'_cluster/nodes/stats',
'_cluster/stats',
@@ -1057,7 +1044,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/', [
{
name: 'Endpoints with slashes - before slash',
- cursor: { row: 0, column: 7 },
+ cursor: { lineNumber: 1, column: 8 },
autoCompleteSet: [
'_cluster/nodes/stats',
'_cluster/stats',
@@ -1070,7 +1057,7 @@ describe('Integration', () => {
},
{
name: 'Endpoints with slashes - on slash',
- cursor: { row: 0, column: 12 },
+ cursor: { lineNumber: 1, column: 13 },
autoCompleteSet: [
'_cluster/nodes/stats',
'_cluster/stats',
@@ -1083,7 +1070,7 @@ describe('Integration', () => {
},
{
name: 'Endpoints with slashes - after slash',
- cursor: { row: 0, column: 13 },
+ cursor: { lineNumber: 1, column: 14 },
autoCompleteSet: ['nodes/stats', 'stats'],
prefixToAdd: '',
suffixToAdd: '',
@@ -1093,7 +1080,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/no', [
{
name: 'Endpoints with slashes - after slash',
- cursor: { row: 0, column: 14 },
+ cursor: { lineNumber: 1, column: 15 },
autoCompleteSet: [
{ name: 'nodes/stats', meta: 'endpoint' },
{ name: 'stats', meta: 'endpoint' },
@@ -1107,7 +1094,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/nodes/st', [
{
name: 'Endpoints with two slashes',
- cursor: { row: 0, column: 20 },
+ cursor: { lineNumber: 1, column: 21 },
autoCompleteSet: ['stats'],
prefixToAdd: '',
suffixToAdd: '',
@@ -1118,7 +1105,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET ', [
{
name: 'Immediately after space + method',
- cursor: { row: 0, column: 4 },
+ cursor: { lineNumber: 1, column: 5 },
autoCompleteSet: [
{ name: '_cluster/nodes/stats', meta: 'endpoint' },
{ name: '_cluster/stats', meta: 'endpoint' },
@@ -1135,7 +1122,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET cl', [
{
name: 'Endpoints by subpart GET',
- cursor: { row: 0, column: 6 },
+ cursor: { lineNumber: 1, column: 7 },
autoCompleteSet: [
{ name: '_cluster/nodes/stats', meta: 'endpoint' },
{ name: '_cluster/stats', meta: 'endpoint' },
@@ -1153,7 +1140,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'POST cl', [
{
name: 'Endpoints by subpart POST',
- cursor: { row: 0, column: 7 },
+ cursor: { lineNumber: 1, column: 8 },
no_context: true,
prefixToAdd: '',
suffixToAdd: '',
@@ -1164,7 +1151,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?', [
{
name: 'Params just after ?',
- cursor: { row: 0, column: 12 },
+ cursor: { lineNumber: 1, column: 13 },
autoCompleteSet: [
{ name: 'filter_path', meta: 'param', insertValue: 'filter_path=' },
{ name: 'format', meta: 'param', insertValue: 'format=' },
@@ -1180,7 +1167,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=', [
{
name: 'Params values',
- cursor: { row: 0, column: 19 },
+ cursor: { lineNumber: 1, column: 20 },
autoCompleteSet: [
{ name: 'json', meta: 'format' },
{ name: 'yaml', meta: 'format' },
@@ -1193,7 +1180,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&', [
{
name: 'Params after amp',
- cursor: { row: 0, column: 24 },
+ cursor: { lineNumber: 1, column: 25 },
autoCompleteSet: [
{ name: 'filter_path', meta: 'param', insertValue: 'filter_path=' },
{ name: 'format', meta: 'param', insertValue: 'format=' },
@@ -1209,7 +1196,7 @@ describe('Integration', () => {
contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&search', [
{
name: 'Params on existing param',
- cursor: { row: 0, column: 26 },
+ cursor: { lineNumber: 1, column: 27 },
rangeToReplace: {
start: { lineNumber: 1, column: 25 },
end: { lineNumber: 1, column: 31 },
@@ -1234,7 +1221,7 @@ describe('Integration', () => {
[
{
name: 'Params on existing value',
- cursor: { row: 0, column: 37 },
+ cursor: { lineNumber: 1, column: 38 },
rangeToReplace: {
start: { lineNumber: 1, column: 37 },
end: { lineNumber: 1, column: 40 },
@@ -1257,7 +1244,7 @@ describe('Integration', () => {
[
{
name: 'Params on just after = with existing value',
- cursor: { row: 0, column: 36 },
+ cursor: { lineNumber: 1, column: 37 },
rangeToReplace: {
start: { lineNumber: 1, column: 37 },
end: { lineNumber: 1, column: 37 },
@@ -1286,7 +1273,7 @@ describe('Integration', () => {
[
{
name: 'fullurl - existing dictionary key, no template',
- cursor: { row: 1, column: 6 },
+ cursor: { lineNumber: 2, column: 7 },
initialValue: 'query',
addTemplate: false,
prefixToAdd: '',
@@ -1299,7 +1286,7 @@ describe('Integration', () => {
},
{
name: 'fullurl - existing inner dictionary key',
- cursor: { row: 2, column: 7 },
+ cursor: { lineNumber: 3, column: 8 },
initialValue: 'field',
addTemplate: false,
prefixToAdd: '',
@@ -1312,7 +1299,7 @@ describe('Integration', () => {
},
{
name: 'fullurl - existing dictionary key, yes template',
- cursor: { row: 4, column: 7 },
+ cursor: { lineNumber: 5, column: 8 },
initialValue: 'facets',
addTemplate: true,
prefixToAdd: '',
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/editor.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js
similarity index 77%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/editor.test.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js
index f828106e2bd41..ae66b1aa8e755 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/editor.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js
@@ -16,17 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-import './setup_mocks';
+import '../sense_editor.test.mocks';
+
import $ from 'jquery';
import _ from 'lodash';
-import ace from 'brace';
-import 'brace/mode/json';
-import { initializeEditor } from '../../src/input';
+import { create } from '../create';
const editorInput1 = require('./editor_input1.txt');
-const utils = require('../../src/utils');
-
-const aceRange = ace.acequire('ace/range');
+const utils = require('../../../../lib/utils/utils');
describe('Editor', () => {
let input;
@@ -40,26 +37,22 @@ describe('Editor', () => {
`;
- input = initializeEditor(
- $('#ConAppEditor'),
- $('#ConAppEditorActions'),
+ input = create(
+ document.querySelector('#ConAppEditor')
);
- input.$el.show();
+ $(input.getCoreEditor().getContainer()).show();
input.autocomplete._test.removeChangeListener();
});
afterEach(function () {
- input.$el.hide();
+ $(input.getCoreEditor().getContainer()).hide();
input.autocomplete._test.addChangeListener();
});
let testCount = 0;
- const callWithEditorMethod = (editorMethod, fn) => (done) => {
- try {
- input[editorMethod](results => fn(results, done));
- } catch {
- done();
- }
+ const callWithEditorMethod = (editorMethod, fn) => async (done) => {
+ const results = await input[editorMethod]();
+ fn(results, done);
};
function utilsTest(name, prefix, data, testToRun) {
@@ -79,10 +72,9 @@ describe('Editor', () => {
data = prefix;
}
- test('Utils test ' + id + ' : ' + name, function (done) {
- input.update(data, function () {
- testToRun(done);
- });
+ test('Utils test ' + id + ' : ' + name, async function (done) {
+ await input.update(data, true);
+ testToRun(done);
});
}
@@ -126,8 +118,7 @@ describe('Editor', () => {
simpleRequest.prefix,
simpleRequest.data,
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 3, 1);
- compareRequest(range, expected);
+ compareRequest(range, { start: { lineNumber: 1, column: 1 }, end: { lineNumber: 4, column: 2 } });
done();
})
);
@@ -152,8 +143,10 @@ describe('Editor', () => {
' ' + simpleRequest.prefix,
simpleRequest.data,
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 3, 1);
- expect(range).toEqual(expected);
+ expect(range).toEqual({
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 4, column: 2 }
+ });
done();
})
);
@@ -180,8 +173,10 @@ describe('Editor', () => {
simpleRequest.prefix + ' ',
simpleRequest.data + ' ',
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 3, 1);
- compareRequest(range, expected);
+ compareRequest(range, {
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 4, column: 2 }
+ });
done();
})
);
@@ -208,8 +203,10 @@ describe('Editor', () => {
singleLineRequest.prefix,
singleLineRequest.data,
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 1, 32);
- compareRequest(range, expected);
+ compareRequest(range, {
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 2, column: 33 }
+ });
done();
})
);
@@ -234,8 +231,10 @@ describe('Editor', () => {
getRequestNoData.prefix,
'\n',
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 0, 10);
- compareRequest(range, expected);
+ compareRequest(range, {
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 1, column: 11 },
+ });
done();
})
);
@@ -260,8 +259,10 @@ describe('Editor', () => {
getRequestNoData.prefix,
getRequestNoData.data,
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 0, 10);
- expect(range).toEqual(expected);
+ expect(range).toEqual({
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 1, column: 11 },
+ });
done();
})
);
@@ -286,8 +287,10 @@ describe('Editor', () => {
multiDocRequest.prefix,
multiDocRequest.data,
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 2, 14);
- expect(range).toEqual(expected);
+ expect(range).toEqual({
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 3, column: 15 },
+ });
done();
})
);
@@ -323,8 +326,10 @@ describe('Editor', () => {
scriptRequest.prefix,
scriptRequest.data,
callWithEditorMethod('getRequestRange', (range, done) => {
- const expected = new aceRange.Range(0, 0, 5, 1);
- compareRequest(range, expected);
+ compareRequest(range, {
+ start: { lineNumber: 1, column: 1 },
+ end: { lineNumber: 6, column: 2 },
+ });
done();
})
);
@@ -347,24 +352,23 @@ describe('Editor', () => {
);
function multiReqTest(name, editorInput, range, expected) {
- utilsTest('multi request select - ' + name, editorInput, function (done) {
- input.getRequestsInRange(range, function (requests) {
- // convert to format returned by request.
- _.each(expected, function (req) {
- req.data =
- req.data == null ? [] : [JSON.stringify(req.data, null, 2)];
- });
-
- compareRequest(requests, expected);
- done();
+ utilsTest('multi request select - ' + name, editorInput, async function (done) {
+ const requests = await input.getRequestsInRange(range, false);
+ // convert to format returned by request.
+ _.each(expected, function (req) {
+ req.data =
+ req.data == null ? [] : [JSON.stringify(req.data, null, 2)];
});
+
+ compareRequest(requests, expected);
+ done();
});
}
multiReqTest(
'mid body to mid body',
editorInput1,
- { start: { row: 12 }, end: { row: 17 } },
+ { start: { lineNumber: 13 }, end: { lineNumber: 18 } },
[
{
method: 'PUT',
@@ -386,7 +390,7 @@ describe('Editor', () => {
multiReqTest(
'single request start to end',
editorInput1,
- { start: { row: 10 }, end: { row: 13 } },
+ { start: { lineNumber: 11 }, end: { lineNumber: 14 } },
[
{
method: 'PUT',
@@ -401,7 +405,7 @@ describe('Editor', () => {
multiReqTest(
'start to end, with comment',
editorInput1,
- { start: { row: 6 }, end: { row: 13 } },
+ { start: { lineNumber: 7 }, end: { lineNumber: 14 } },
[
{
method: 'GET',
@@ -421,7 +425,7 @@ describe('Editor', () => {
multiReqTest(
'before start to after end, with comments',
editorInput1,
- { start: { row: 4 }, end: { row: 14 } },
+ { start: { lineNumber: 5 }, end: { lineNumber: 15 } },
[
{
method: 'GET',
@@ -441,37 +445,36 @@ describe('Editor', () => {
multiReqTest(
'between requests',
editorInput1,
- { start: { row: 21 }, end: { row: 22 } },
+ { start: { lineNumber: 22 }, end: { lineNumber: 23 } },
[]
);
multiReqTest(
'between requests - with comment',
editorInput1,
- { start: { row: 20 }, end: { row: 22 } },
+ { start: { lineNumber: 21 }, end: { lineNumber: 23 } },
[]
);
multiReqTest(
'between requests - before comment',
editorInput1,
- { start: { row: 19 }, end: { row: 22 } },
+ { start: { lineNumber: 20 }, end: { lineNumber: 23 } },
[]
);
function multiReqCopyAsCurlTest(name, editorInput, range, expected) {
- utilsTest('multi request copy as curl - ' + name, editorInput, function (done) {
- input.getRequestsAsCURL(range, function (curl) {
- expect(curl).toEqual(expected);
- done();
- });
+ utilsTest('multi request copy as curl - ' + name, editorInput, async function (done) {
+ const curl = await input.getRequestsAsCURL('http://localhost:9200', range);
+ expect(curl).toEqual(expected);
+ done();
});
}
multiReqCopyAsCurlTest(
'start to end, with comment',
editorInput1,
- { start: { row: 6 }, end: { row: 13 } },
+ { start: { lineNumber: 7 }, end: { lineNumber: 14 } },
`
curl -XGET "http://localhost:9200/_stats?level=shards"
diff --git a/src/legacy/ui/public/management/index_pattern_list/index_pattern_list_config.js b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts
similarity index 69%
rename from src/legacy/ui/public/management/index_pattern_list/index_pattern_list_config.js
rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts
index cf1389fbab9f5..33508a2f63299 100644
--- a/src/legacy/ui/public/management/index_pattern_list/index_pattern_list_config.js
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts
@@ -17,21 +17,16 @@
* under the License.
*/
-export class IndexPatternListConfig {
- static key = 'default';
+import { SenseEditor } from './sense_editor';
+import * as core from '../legacy_core_editor';
- getIndexPatternTags = (indexPattern, isDefault) => {
- return isDefault ? [{
- key: 'default',
- name: 'Default',
- }] : [];
- }
+export function create(element: HTMLElement) {
+ const coreEditor = core.create(element);
+ const senseEditor = new SenseEditor(coreEditor);
- getFieldInfo = () => {
- return [];
- }
-
- areScriptedFieldsEnabled = () => {
- return true;
- }
+ /**
+ * Init the editor
+ */
+ senseEditor.highlightCurrentRequestsAndUpdateActionBar();
+ return senseEditor;
}
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts
new file mode 100644
index 0000000000000..d56a9cca0ef32
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+function detectCURLinLine(line: string) {
+ // returns true if text matches a curl request
+ return line.match(/^\s*?curl\s+(-X[A-Z]+)?\s*['"]?.*?['"]?(\s*$|\s+?-d\s*?['"])/);
+}
+
+export function detectCURL(text: string) {
+ // returns true if text matches a curl request
+ if (!text) return false;
+ for (const line of text.split('\n')) {
+ if (detectCURLinLine(line)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+export function parseCURL(text: string) {
+ let state = 'NONE';
+ const out = [];
+ let body: any[] = [];
+ let line = '';
+ const lines = text.trim().split('\n');
+ let matches;
+
+ const EmptyLine = /^\s*$/;
+ const Comment = /^\s*(?:#|\/{2,})(.*)\n?$/;
+ const ExecutionComment = /^\s*#!/;
+ const ClosingSingleQuote = /^([^']*)'/;
+ const ClosingDoubleQuote = /^((?:[^\\"]|\\.)*)"/;
+ const EscapedQuotes = /^((?:[^\\"']|\\.)+)/;
+
+ const LooksLikeCurl = /^\s*curl\s+/;
+ const CurlVerb = /-X ?(GET|HEAD|POST|PUT|DELETE)/;
+
+ const HasProtocol = /[\s"']https?:\/\//;
+ const CurlRequestWithProto = /[\s"']https?:\/\/[^\/ ]+\/+([^\s"']+)/;
+ const CurlRequestWithoutProto = /[\s"'][^\/ ]+\/+([^\s"']+)/;
+ const CurlData = /^.+\s(--data|-d)\s*/;
+ const SenseLine = /^\s*(GET|HEAD|POST|PUT|DELETE)\s+\/?(.+)/;
+
+ if (lines.length > 0 && ExecutionComment.test(lines[0])) {
+ lines.shift();
+ }
+
+ function nextLine() {
+ if (line.length > 0) {
+ return true;
+ }
+ if (lines.length === 0) {
+ return false;
+ }
+ line = lines.shift()!.replace(/[\r\n]+/g, '\n') + '\n';
+ return true;
+ }
+
+ function unescapeLastBodyEl() {
+ const str = body.pop().replace(/\\([\\"'])/g, '$1');
+ body.push(str);
+ }
+
+ // Is the next char a single or double quote?
+ // If so remove it
+ function detectQuote() {
+ if (line.substr(0, 1) === "'") {
+ line = line.substr(1);
+ state = 'SINGLE_QUOTE';
+ } else if (line.substr(0, 1) === '"') {
+ line = line.substr(1);
+ state = 'DOUBLE_QUOTE';
+ } else {
+ state = 'UNQUOTED';
+ }
+ }
+
+ // Body is finished - append to output with final LF
+ function addBodyToOut() {
+ if (body.length > 0) {
+ out.push(body.join(''));
+ body = [];
+ }
+ state = 'LF';
+ out.push('\n');
+ }
+
+ // If the pattern matches, then the state is about to change,
+ // so add the capture to the body and detect the next state
+ // Otherwise add the whole line
+ function consumeMatching(pattern: string | RegExp) {
+ const result = line.match(pattern);
+ if (result) {
+ body.push(result[1]);
+ line = line.substr(result[0].length);
+ detectQuote();
+ } else {
+ body.push(line);
+ line = '';
+ }
+ }
+
+ function parseCurlLine() {
+ let verb = 'GET';
+ let request = '';
+ let result;
+ if ((result = line.match(CurlVerb))) {
+ verb = result[1];
+ }
+
+ // JS regexen don't support possessive quantifiers, so
+ // we need two distinct patterns
+ const pattern = HasProtocol.test(line) ? CurlRequestWithProto : CurlRequestWithoutProto;
+
+ if ((result = line.match(pattern))) {
+ request = result[1];
+ }
+
+ out.push(verb + ' /' + request + '\n');
+
+ if ((result = line.match(CurlData))) {
+ line = line.substr(result[0].length);
+ detectQuote();
+ if (EmptyLine.test(line)) {
+ line = '';
+ }
+ } else {
+ state = 'NONE';
+ line = '';
+ out.push('');
+ }
+ }
+
+ while (nextLine()) {
+ if (state === 'SINGLE_QUOTE') {
+ consumeMatching(ClosingSingleQuote);
+ } else if (state === 'DOUBLE_QUOTE') {
+ consumeMatching(ClosingDoubleQuote);
+ unescapeLastBodyEl();
+ } else if (state === 'UNQUOTED') {
+ consumeMatching(EscapedQuotes);
+ if (body.length) {
+ unescapeLastBodyEl();
+ }
+ if (state === 'UNQUOTED') {
+ addBodyToOut();
+ line = '';
+ }
+ }
+
+ // the BODY state (used to match the body of a Sense request)
+ // can be terminated early if it encounters
+ // a comment or an empty line
+ else if (state === 'BODY') {
+ if (Comment.test(line) || EmptyLine.test(line)) {
+ addBodyToOut();
+ } else {
+ body.push(line);
+ line = '';
+ }
+ } else if (EmptyLine.test(line)) {
+ if (state !== 'LF') {
+ out.push('\n');
+ state = 'LF';
+ }
+ line = '';
+ } else if ((matches = line.match(Comment))) {
+ out.push('#' + matches[1] + '\n');
+ state = 'NONE';
+ line = '';
+ } else if (LooksLikeCurl.test(line)) {
+ parseCurlLine();
+ } else if ((matches = line.match(SenseLine))) {
+ out.push(matches[1] + ' /' + matches[2] + '\n');
+ line = '';
+ state = 'BODY';
+ }
+
+ // Nothing else matches, so output with a prefix of ### for debugging purposes
+ else {
+ out.push('### ' + line);
+ line = '';
+ }
+ }
+
+ addBodyToOut();
+ return out.join('').trim();
+}
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts
new file mode 100644
index 0000000000000..9310de2724fbe
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts
@@ -0,0 +1,23 @@
+/*
+ * 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 * from './create';
+export * from '../legacy_core_editor/create_readonly';
+export { MODE } from '../../../lib/row_parser';
+export { SenseEditor } from './sense_editor';
diff --git a/src/plugins/data/public/index_patterns/types.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts
similarity index 69%
rename from src/plugins/data/public/index_patterns/types.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts
index 59e3075bf215d..8df9bb8ef9a0b 100644
--- a/src/plugins/data/public/index_patterns/types.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts
@@ -16,8 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
+/* eslint no-undef: 0 */
-import { IndexPatternsService } from './index_patterns_service';
+import '../legacy_core_editor/legacy_core_editor.test.mocks';
-export type IndexPatternsSetup = ReturnType;
-export type IndexPatternsStart = ReturnType;
+// TODO: Remove this mock
+jest.mock('../../../application', () => ({ legacyBackDoorToSettings: () => {} }));
+
+import jQuery from 'jquery';
+jest.spyOn(jQuery, 'ajax').mockImplementation(
+ () =>
+ new Promise(() => {
+ // never resolve
+ }) as any
+);
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts
new file mode 100644
index 0000000000000..9679eaa2884ce
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts
@@ -0,0 +1,502 @@
+/*
+ * 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 _ from 'lodash';
+import RowParser from '../../../lib/row_parser';
+import * as utils from '../../../lib/utils/utils';
+// @ts-ignore
+import * as es from '../../../lib/es/es';
+
+import { CoreEditor, Position, Range } from '../../../types';
+import { createTokenIterator } from '../../factories';
+
+import Autocomplete from '../../../lib/autocomplete/autocomplete';
+
+export class SenseEditor {
+ currentReqRange: (Range & { markerRef: any }) | null;
+ parser: any;
+
+ // @ts-ignore
+ private readonly autocomplete: any;
+
+ constructor(private readonly coreEditor: CoreEditor) {
+ this.currentReqRange = null;
+ this.parser = new RowParser(this.coreEditor);
+ this.autocomplete = new (Autocomplete as any)({
+ coreEditor,
+ parser: this.parser,
+ });
+ this.coreEditor.on(
+ 'tokenizerUpdate',
+ this.highlightCurrentRequestsAndUpdateActionBar.bind(this)
+ );
+ this.coreEditor.on('changeCursor', this.highlightCurrentRequestsAndUpdateActionBar.bind(this));
+ this.coreEditor.on('changeScrollTop', this.updateActionsBar.bind(this));
+ }
+
+ prevRequestStart = (rowOrPos?: number | Position): Position => {
+ let curRow: number;
+
+ if (rowOrPos == null) {
+ curRow = this.coreEditor.getCurrentPosition().lineNumber;
+ } else if (_.isObject(rowOrPos)) {
+ curRow = (rowOrPos as Position).lineNumber;
+ } else {
+ curRow = rowOrPos as number;
+ }
+
+ while (curRow > 0 && !this.parser.isStartRequestRow(curRow, this.coreEditor)) curRow--;
+
+ return {
+ lineNumber: curRow,
+ column: 1,
+ };
+ };
+
+ nextRequestStart = (rowOrPos?: number | Position) => {
+ let curRow: number;
+ if (rowOrPos == null) {
+ curRow = this.coreEditor.getCurrentPosition().lineNumber;
+ } else if (_.isObject(rowOrPos)) {
+ curRow = (rowOrPos as Position).lineNumber;
+ } else {
+ curRow = rowOrPos as number;
+ }
+ const maxLines = this.coreEditor.getValue().split('\n').length;
+ for (; curRow < maxLines - 1; curRow++) {
+ if (this.parser.isStartRequestRow(curRow, this.coreEditor)) {
+ break;
+ }
+ }
+ return {
+ row: curRow,
+ column: 0,
+ };
+ };
+
+ autoIndent = _.debounce(async () => {
+ await this.coreEditor.waitForLatestTokens();
+ const reqRange = await this.getRequestRange();
+ if (!reqRange) {
+ return;
+ }
+ const parsedReq = await this.getRequest();
+
+ if (!parsedReq) {
+ return;
+ }
+
+ if (parsedReq.data && parsedReq.data.length > 0) {
+ let indent = parsedReq.data.length === 1; // unindent multi docs by default
+ let formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent);
+ if (!formattedData.changed) {
+ // toggle.
+ indent = !indent;
+ formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent);
+ }
+ parsedReq.data = formattedData.data;
+
+ this.replaceRequestRange(parsedReq, reqRange);
+ }
+ }, 25);
+
+ update = async (data: string, reTokenizeAll = false) => {
+ return this.coreEditor.setValue(data, reTokenizeAll);
+ };
+
+ replaceRequestRange = (newRequest: any, requestRange: Range) => {
+ const text = utils.textFromRequest(newRequest);
+ if (requestRange) {
+ this.coreEditor.replaceRange(requestRange, text);
+ } else {
+ // just insert where we are
+ this.coreEditor.insert(this.coreEditor.getCurrentPosition(), text);
+ }
+ };
+
+ getRequestRange = async (lineNumber?: number): Promise => {
+ await this.coreEditor.waitForLatestTokens();
+
+ if (this.parser.isInBetweenRequestsRow(lineNumber)) {
+ return null;
+ }
+
+ const reqStart = this.prevRequestStart(lineNumber);
+ const reqEnd = this.nextRequestEnd(reqStart);
+
+ return {
+ start: {
+ ...reqStart,
+ },
+ end: {
+ ...reqEnd,
+ },
+ };
+ };
+
+ expandRangeToRequestEdges = async (
+ range = this.coreEditor.getSelectionRange()
+ ): Promise => {
+ await this.coreEditor.waitForLatestTokens();
+
+ let startLineNumber = range.start.lineNumber;
+ let endLineNumber = range.end.lineNumber;
+ const maxLine = Math.max(1, this.coreEditor.getLineCount());
+
+ if (this.parser.isInBetweenRequestsRow(startLineNumber)) {
+ /* Do nothing... */
+ } else {
+ for (; startLineNumber >= 1; startLineNumber--) {
+ if (this.parser.isStartRequestRow(startLineNumber)) {
+ break;
+ }
+ }
+ }
+
+ if (startLineNumber < 1 || startLineNumber > endLineNumber) {
+ return null;
+ }
+ // move end row to the previous request end if between requests, otherwise walk forward
+ if (this.parser.isInBetweenRequestsRow(endLineNumber)) {
+ for (; endLineNumber >= startLineNumber; endLineNumber--) {
+ if (this.parser.isEndRequestRow(endLineNumber)) {
+ break;
+ }
+ }
+ } else {
+ for (; endLineNumber <= maxLine; endLineNumber++) {
+ if (this.parser.isEndRequestRow(endLineNumber)) {
+ break;
+ }
+ }
+ }
+
+ if (endLineNumber < startLineNumber || endLineNumber > maxLine) {
+ return null;
+ }
+
+ const endColumn =
+ (this.coreEditor.getLineValue(endLineNumber) || '').replace(/\s+$/, '').length + 1;
+ return {
+ start: {
+ lineNumber: startLineNumber,
+ column: 1,
+ },
+ end: {
+ lineNumber: endLineNumber,
+ column: endColumn,
+ },
+ };
+ };
+
+ getRequestInRange = async (range?: Range) => {
+ await this.coreEditor.waitForLatestTokens();
+ if (!range) {
+ return null;
+ }
+ const request: {
+ method: string;
+ data: string[];
+ url: string | null;
+ range: Range;
+ } = {
+ method: '',
+ data: [],
+ url: null,
+ range,
+ };
+
+ const pos = range.start;
+ const tokenIter = createTokenIterator({ editor: this.coreEditor, position: pos });
+ let t = tokenIter.getCurrentToken();
+ if (this.parser.isEmptyToken(t)) {
+ // if the row starts with some spaces, skip them.
+ t = this.parser.nextNonEmptyToken(tokenIter);
+ }
+ if (t == null) {
+ return null;
+ }
+
+ request.method = t.value;
+ t = this.parser.nextNonEmptyToken(tokenIter);
+
+ if (!t || t.type === 'method') {
+ return null;
+ }
+
+ request.url = '';
+
+ while (t && t.type && t.type.indexOf('url') === 0) {
+ request.url += t.value;
+ t = tokenIter.stepForward();
+ }
+ if (this.parser.isEmptyToken(t)) {
+ // if the url row ends with some spaces, skip them.
+ t = this.parser.nextNonEmptyToken(tokenIter);
+ }
+ let bodyStartLineNumber = (t ? 0 : 1) + tokenIter.getCurrentPosition().lineNumber; // artificially increase end of docs.
+ let dataEndPos: Position;
+ while (
+ bodyStartLineNumber < range.end.lineNumber ||
+ (bodyStartLineNumber === range.end.lineNumber && 1 < range.end.column)
+ ) {
+ dataEndPos = this.nextDataDocEnd({
+ lineNumber: bodyStartLineNumber,
+ column: 1,
+ });
+ const bodyRange: Range = {
+ start: {
+ lineNumber: bodyStartLineNumber,
+ column: 1,
+ },
+ end: dataEndPos,
+ };
+ const data = this.coreEditor.getValueInRange(bodyRange)!;
+ request.data.push(data.trim());
+ bodyStartLineNumber = dataEndPos.lineNumber + 1;
+ }
+
+ return request;
+ };
+
+ getRequestsInRange = async (
+ range = this.coreEditor.getSelectionRange(),
+ includeNonRequestBlocks = false
+ ): Promise => {
+ await this.coreEditor.waitForLatestTokens();
+ if (!range) {
+ return [];
+ }
+
+ const expandedRange = await this.expandRangeToRequestEdges(range);
+
+ if (!expandedRange) {
+ return [];
+ }
+
+ const requests: any = [];
+
+ let rangeStartCursor = expandedRange.start.lineNumber;
+ const endLineNumber = expandedRange.end.lineNumber;
+
+ // move to the next request start (during the second iterations this may not be exactly on a request
+ let currentLineNumber = expandedRange.start.lineNumber;
+
+ const flushNonRequestBlock = () => {
+ if (includeNonRequestBlocks) {
+ const nonRequestPrefixBlock = this.coreEditor
+ .getLines(rangeStartCursor, currentLineNumber - 1)
+ .join('\n');
+ if (nonRequestPrefixBlock) {
+ requests.push(nonRequestPrefixBlock);
+ }
+ }
+ };
+
+ while (currentLineNumber <= endLineNumber) {
+ if (this.parser.isStartRequestRow(currentLineNumber)) {
+ flushNonRequestBlock();
+ const request = await this.getRequest(currentLineNumber);
+ if (!request) {
+ // Something has probably gone wrong.
+ return requests;
+ } else {
+ requests.push(request);
+ rangeStartCursor = currentLineNumber = request.range.end.lineNumber + 1;
+ }
+ } else {
+ ++currentLineNumber;
+ }
+ }
+
+ flushNonRequestBlock();
+
+ return requests;
+ };
+
+ getRequest = async (row?: number) => {
+ await this.coreEditor.waitForLatestTokens();
+ if (this.parser.isInBetweenRequestsRow(row)) {
+ return null;
+ }
+
+ const range = await this.getRequestRange(row);
+ return this.getRequestInRange(range!);
+ };
+
+ moveToPreviousRequestEdge = async () => {
+ await this.coreEditor.waitForLatestTokens();
+ const pos = this.coreEditor.getCurrentPosition();
+ for (
+ pos.lineNumber--;
+ pos.lineNumber > 1 && !this.parser.isRequestEdge(pos.lineNumber);
+ pos.lineNumber--
+ ) {
+ // loop for side effects
+ }
+ this.coreEditor.moveCursorToPosition({
+ lineNumber: pos.lineNumber,
+ column: 1,
+ });
+ };
+
+ moveToNextRequestEdge = async (moveOnlyIfNotOnEdge: boolean) => {
+ await this.coreEditor.waitForLatestTokens();
+ const pos = this.coreEditor.getCurrentPosition();
+ const maxRow = this.coreEditor.getLineCount();
+ if (!moveOnlyIfNotOnEdge) {
+ pos.lineNumber++;
+ }
+ for (
+ ;
+ pos.lineNumber < maxRow && !this.parser.isRequestEdge(pos.lineNumber);
+ pos.lineNumber++
+ ) {
+ // loop for side effects
+ }
+ this.coreEditor.moveCursorToPosition({
+ lineNumber: pos.lineNumber,
+ column: 1,
+ });
+ };
+
+ nextRequestEnd = (pos: Position): Position => {
+ pos = pos || this.coreEditor.getCurrentPosition();
+ const maxLines = this.coreEditor.getLineCount();
+ let curLineNumber = pos.lineNumber;
+ for (; curLineNumber <= maxLines; ++curLineNumber) {
+ const curRowMode = this.parser.getRowParseMode(curLineNumber);
+ // eslint-disable-next-line no-bitwise
+ if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) {
+ break;
+ }
+ // eslint-disable-next-line no-bitwise
+ if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) {
+ break;
+ }
+ }
+
+ const column =
+ (this.coreEditor.getLineValue(curLineNumber) || '').replace(/\s+$/, '').length + 1;
+
+ return {
+ lineNumber: curLineNumber,
+ column,
+ };
+ };
+
+ nextDataDocEnd = (pos: Position): Position => {
+ pos = pos || this.coreEditor.getCurrentPosition();
+ let curLineNumber = pos.lineNumber;
+ const maxLines = this.coreEditor.getLineCount();
+ for (; curLineNumber < maxLines; curLineNumber++) {
+ const curRowMode = this.parser.getRowParseMode(curLineNumber);
+ // eslint-disable-next-line no-bitwise
+ if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) {
+ break;
+ }
+ // eslint-disable-next-line no-bitwise
+ if ((curRowMode & this.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) {
+ break;
+ }
+ // eslint-disable-next-line no-bitwise
+ if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) {
+ break;
+ }
+ }
+
+ const column =
+ (this.coreEditor.getLineValue(curLineNumber) || '').length +
+ 1 /* Range goes to 1 after last char */;
+
+ return {
+ lineNumber: curLineNumber,
+ column,
+ };
+ };
+
+ highlightCurrentRequestsAndUpdateActionBar = _.debounce(async () => {
+ await this.coreEditor.waitForLatestTokens();
+ const expandedRange = await this.expandRangeToRequestEdges();
+ if (expandedRange === null && this.currentReqRange === null) {
+ return;
+ }
+ if (
+ expandedRange !== null &&
+ this.currentReqRange !== null &&
+ expandedRange.start.lineNumber === this.currentReqRange.start.lineNumber &&
+ expandedRange.end.lineNumber === this.currentReqRange.end.lineNumber
+ ) {
+ // same request, now see if we are on the first line and update the action bar
+ const cursorLineNumber = this.coreEditor.getCurrentPosition().lineNumber;
+ if (cursorLineNumber === this.currentReqRange.start.lineNumber) {
+ this.updateActionsBar();
+ }
+ return; // nothing to do..
+ }
+
+ if (this.currentReqRange) {
+ this.coreEditor.removeMarker(this.currentReqRange.markerRef);
+ }
+
+ this.currentReqRange = expandedRange as any;
+ if (this.currentReqRange) {
+ this.currentReqRange.markerRef = this.coreEditor.addMarker(this.currentReqRange);
+ }
+ this.updateActionsBar();
+ }, 25);
+
+ getRequestsAsCURL = async (elasticsearchBaseUrl: string, range?: Range): Promise => {
+ const requests = await this.getRequestsInRange(range, true);
+ const result = _.map(requests, req => {
+ if (typeof req === 'string') {
+ // no request block
+ return req;
+ }
+
+ const esPath = req.url;
+ const esMethod = req.method;
+ const esData = req.data;
+
+ // this is the first url defined in elasticsearch.hosts
+ const url = es.constructESUrl(elasticsearchBaseUrl, esPath);
+
+ let ret = 'curl -X' + esMethod + ' "' + url + '"';
+ if (esData && esData.length) {
+ ret += " -H 'Content-Type: application/json' -d'\n";
+ const dataAsString = utils.collapseLiteralStrings(esData.join('\n'));
+ // since Sense doesn't allow single quote json string any single qoute is within a string.
+ ret += dataAsString.replace(/'/g, '\\"');
+ if (esData.length > 1) {
+ ret += '\n';
+ } // end with a new line
+ ret += "'";
+ }
+ return ret;
+ });
+
+ return result.join('\n');
+ };
+
+ updateActionsBar = () => this.coreEditor.legacyUpdateUI(this.currentReqRange);
+
+ getCoreEditor() {
+ return this.coreEditor;
+ }
+}
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/stores/editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/stores/editor.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/stores/request.ts b/src/legacy/core_plugins/console/public/np_ready/application/stores/request.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/application/stores/request.ts
rename to src/legacy/core_plugins/console/public/np_ready/application/stores/request.ts
diff --git a/src/legacy/core_plugins/console/public/quarantined/_app.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/_app.scss
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/_app.scss
rename to src/legacy/core_plugins/console/public/np_ready/application/styles/_app.scss
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/directives/_help.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_help.scss
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/directives/_help.scss
rename to src/legacy/core_plugins/console/public/np_ready/application/styles/components/_help.scss
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/directives/_history.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_history.scss
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/directives/_history.scss
rename to src/legacy/core_plugins/console/public/np_ready/application/styles/components/_history.scss
diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss
new file mode 100644
index 0000000000000..9dfef202d1254
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss
@@ -0,0 +1,2 @@
+@import 'help';
+@import 'history';
diff --git a/src/legacy/core_plugins/console/public/quarantined/index.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss
similarity index 81%
rename from src/legacy/core_plugins/console/public/quarantined/index.scss
rename to src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss
index ce40b2c6f1102..dc45f6cfdacf5 100644
--- a/src/legacy/core_plugins/console/public/quarantined/index.scss
+++ b/src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss
@@ -7,5 +7,5 @@
// conChart__legend--small
// conChart__legend-isLoading
-@import './app';
-@import './src/directives/index';
+@import 'app';
+@import 'components/index';
diff --git a/src/legacy/core_plugins/console/np_ready/public/index.ts b/src/legacy/core_plugins/console/public/np_ready/index.ts
similarity index 93%
rename from src/legacy/core_plugins/console/np_ready/public/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/index.ts
index 3f8d162f62d44..045420f401e3b 100644
--- a/src/legacy/core_plugins/console/np_ready/public/index.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/index.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { PluginInitializerContext } from '../../../../../core/public';
+import { PluginInitializerContext } from 'kibana/public';
import { ConsoleUIPlugin } from './plugin';
diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/index.ts b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.test.ts b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts
similarity index 84%
rename from src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.test.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts
index aecb6cb37ee81..00bfe32c85906 100644
--- a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.test.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts
@@ -17,15 +17,17 @@
* under the License.
*/
-// @ts-ignore
-import '../../../../public/quarantined/tests/src/setup_mocks';
+import '../../application/models/sense_editor/sense_editor.test.mocks';
-import { Editor } from 'brace';
import $ from 'jquery';
-// @ts-ignore
-import { initializeEditor } from '../../../../public/quarantined/src/input.ts';
-import { AceTokensProvider } from '.';
+// TODO:
+// We import from application models as a convenient way to bootstrap loading up of an editor using
+// this lib. We also need to import application specific mocks which is not ideal.
+// In this situation, the token provider lib knows about app models in tests, which it really shouldn't. Should create
+// a better sandbox in future.
+import { create, SenseEditor } from '../../application/models/sense_editor';
+
import { Position, Token, TokensProvider } from '../../types';
interface RunTestArgs {
@@ -34,7 +36,7 @@ interface RunTestArgs {
}
describe('Ace (legacy) token provider', () => {
- let aceEditor: Editor & { $el: any; autocomplete: any; update: any };
+ let senseEditor: SenseEditor;
let tokenProvider: TokensProvider;
beforeEach(() => {
// Set up our document body
@@ -44,16 +46,18 @@ describe('Ace (legacy) token provider', () => {
`;
- aceEditor = initializeEditor($('#ConAppEditor'), $('#ConAppEditorActions'));
+ senseEditor = create(document.querySelector('#ConAppEditor')!);
+
+ $(senseEditor.getCoreEditor().getContainer())!.show();
- aceEditor.$el.show();
- aceEditor.autocomplete._test.removeChangeListener();
- tokenProvider = new AceTokensProvider(aceEditor.session);
+ (senseEditor as any).autocomplete._test.removeChangeListener();
+ tokenProvider = senseEditor.getCoreEditor().getTokenProvider();
});
- afterEach(done => {
- aceEditor.$el.hide();
- aceEditor.autocomplete._test.addChangeListener();
- aceEditor.update('', done);
+
+ afterEach(async () => {
+ $(senseEditor.getCoreEditor().getContainer())!.hide();
+ (senseEditor as any).autocomplete._test.addChangeListener();
+ await senseEditor.update('', true);
});
describe('#getTokens', () => {
@@ -63,7 +67,7 @@ describe('Ace (legacy) token provider', () => {
done,
lineNumber = 1,
}: RunTestArgs & { expectedTokens: Token[] | null; lineNumber?: number }) => {
- aceEditor.update(input, function() {
+ senseEditor.update(input, true).then(() => {
const tokens = tokenProvider.getTokens(lineNumber);
expect(tokens).toEqual(expectedTokens);
if (done) done();
@@ -160,7 +164,7 @@ describe('Ace (legacy) token provider', () => {
test('case 2 - empty lines', done => {
runTest({
input: `GET http://test:user@somehost/
-
+
@@ -182,7 +186,7 @@ describe('Ace (legacy) token provider', () => {
done,
position,
}: RunTestArgs & { expectedToken: Token | null; position: Position }) => {
- aceEditor.update(input, function() {
+ senseEditor.update(input, true).then(() => {
const tokens = tokenProvider.getTokenAt(position);
expect(tokens).toEqual(expectedToken);
if (done) done();
diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.ts b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.ts
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_autocomplete.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js
similarity index 98%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/url_autocomplete.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js
index 154a7e9ba2b4b..77c211a71d986 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_autocomplete.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js
@@ -16,18 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-import './setup_mocks';
-import 'brace';
-import 'brace/mode/javascript';
-import 'brace/mode/json';
+import '../../../application/models/sense_editor/sense_editor.test.mocks';
+
const _ = require('lodash');
import {
URL_PATH_END_MARKER,
UrlPatternMatcher,
ListComponent
-} from '../../src/autocomplete/components';
+} from '../../autocomplete/components';
-import { populateContext } from '../../src/autocomplete/engine';
+import { populateContext } from '../../autocomplete/engine';
describe('Url autocomplete', () => {
function patternsTest(
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_params.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js
similarity index 94%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/url_params.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js
index 7b44d91fa503a..b91c463bb14ff 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_params.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js
@@ -16,13 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
-import './setup_mocks';
+import '../../../application/models/sense_editor/sense_editor.test.mocks';
import 'brace';
import 'brace/mode/javascript';
import 'brace/mode/json';
const _ = require('lodash');
-import { UrlParams } from '../../src/autocomplete/url_params';
-import { populateContext } from '../../src/autocomplete/engine';
+import { UrlParams } from '../../autocomplete/url_params';
+import { populateContext } from '../../autocomplete/engine';
describe('Url params', () => {
function paramTest(
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete.ts b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts
similarity index 94%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts
index 47edf42f0eec5..8edb26f7817e4 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts
@@ -18,7 +18,7 @@
*/
import _ from 'lodash';
-import ace, { Editor as AceEditor, IEditSession, Position as AcePosition } from 'brace';
+import ace, { Editor as AceEditor, IEditSession } from 'brace';
import { i18n } from '@kbn/i18n';
import {
@@ -27,17 +27,18 @@ import {
getGlobalAutocompleteComponents,
getUnmatchedEndpointComponents,
// @ts-ignore
-} from './kb';
-// @ts-ignore
-import utils from './utils';
+} from '../kb/kb';
+
+import * as utils from '../utils/utils';
+
// @ts-ignore
-import { populateContext } from './autocomplete/engine';
+import { populateContext } from './engine';
// @ts-ignore
-import { URL_PATH_END_MARKER } from './autocomplete/components';
-import { createTokenIterator } from '../../../np_ready/public/application/factories';
+import { URL_PATH_END_MARKER } from './components/index';
+import { createTokenIterator } from '../../application/factories';
-import { Position, Token, Range } from '../../../np_ready/public/types';
-import { LegacyEditor } from '../../../np_ready/public/application/models';
+import { Position, Token, Range, CoreEditor } from '../../types';
+import { SenseEditor } from '../../application/models/sense_editor';
let LAST_EVALUATED_TOKEN: any = null;
@@ -54,7 +55,7 @@ function isUrlParamsToken(token: any) {
}
}
function getCurrentMethodAndTokenPaths(
- editor: LegacyEditor,
+ editor: CoreEditor,
pos: Position,
parser: any,
forceEndOfUrl?: boolean
@@ -297,12 +298,12 @@ function getCurrentMethodAndTokenPaths(
}
return ret;
}
-export function getEndpointFromPosition(aceEditor: AceEditor, pos: AcePosition, parser: any) {
- const editor = new LegacyEditor(aceEditor);
+export function getEndpointFromPosition(senseEditor: SenseEditor, pos: Position, parser: any) {
+ const editor = senseEditor.getCoreEditor();
const context = {
...getCurrentMethodAndTokenPaths(
editor,
- { column: pos.column + 1, lineNumber: pos.row + 1 },
+ { column: pos.column, lineNumber: pos.lineNumber },
parser,
true
),
@@ -313,23 +314,7 @@ export function getEndpointFromPosition(aceEditor: AceEditor, pos: AcePosition,
}
// eslint-disable-next-line
-export default function({
- coreEditor: editor,
- parser,
- execCommand,
- getCursorPosition,
- isCompleterActive,
- addChangeListener,
- removeChangeListener,
-}: {
- coreEditor: LegacyEditor;
- parser: any;
- execCommand: (cmd: string) => void;
- getCursorPosition: () => Position | null;
- isCompleterActive: () => boolean;
- addChangeListener: (fn: any) => void;
- removeChangeListener: (fn: any) => void;
-}) {
+export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor; parser: any }) {
function isUrlPathToken(token: Token | null) {
switch ((token || ({} as any)).type) {
case 'url.slash':
@@ -404,7 +389,7 @@ export default function({
valueToInsert = context.prefixToAdd + valueToInsert + context.suffixToAdd;
// disable listening to the changes we are making.
- removeChangeListener(editorChangeListener);
+ editor.off('changeSelection', editorChangeListener);
if (context.rangeToReplace.start.column !== context.rangeToReplace.end.column) {
editor.replace(context.rangeToReplace, valueToInsert);
@@ -456,10 +441,10 @@ export default function({
}
// re-enable listening to typing
- addChangeListener(editorChangeListener);
+ editor.on('changeSelection', editorChangeListener);
}
- function getAutoCompleteContext(ctxEditor: LegacyEditor, pos: Position) {
+ function getAutoCompleteContext(ctxEditor: CoreEditor, pos: Position) {
// deduces all the parameters need to position and insert the auto complete
const context: any = {
autoCompleteSet: null, // instructions for what can be here
@@ -567,10 +552,8 @@ export default function({
// in between request on an empty
if (editor.getLineValue(pos.lineNumber).trim() === '') {
- // check if the previous line is a single line begging of a new request
- rowMode = parser.getRowParseMode(
- pos.lineNumber - 1 - 1 /* see RowParser for why the added -1, for now */
- );
+ // check if the previous line is a single line beginning of a new request
+ rowMode = parser.getRowParseMode(pos.lineNumber - 1);
// eslint-disable-next-line no-bitwise
if (
// eslint-disable-next-line no-bitwise
@@ -964,23 +947,23 @@ export default function({
}
LAST_EVALUATED_TOKEN = currentToken;
- execCommand('startAutocomplete');
+ editor.execCommand('startAutocomplete');
},
100);
function editorChangeListener() {
- const position = getCursorPosition();
- if (position && !isCompleterActive()) {
+ const position = editor.getCurrentPosition();
+ if (position && !editor.isCompleterActive()) {
evaluateCurrentTokenAfterAChange(position);
}
}
function getCompletions(
DO_NOT_USE: AceEditor,
- session: IEditSession,
- pos: any,
- prefix: any,
- callback: any
+ DO_NOT_USE_SESSION: IEditSession,
+ pos: { row: number; column: number },
+ prefix: string,
+ callback: (...args: any[]) => void
) {
const position: Position = {
lineNumber: pos.row + 1,
@@ -1054,7 +1037,7 @@ export default function({
}
}
- addChangeListener(editorChangeListener);
+ editor.on('changeSelection', editorChangeListener);
// Hook into Ace
@@ -1090,8 +1073,8 @@ export default function({
_test: {
getCompletions,
addReplacementInfoToContext,
- addChangeListener: () => addChangeListener(editorChangeListener),
- removeChangeListener: () => removeChangeListener(editorChangeListener),
+ addChangeListener: () => editor.on('changeSelection', editorChangeListener),
+ removeChangeListener: () => editor.off('changeSelection', editorChangeListener),
},
};
}
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/body_completer.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/body_completer.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/body_completer.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/body_completer.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/accept_endpoint_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/accept_endpoint_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/accept_endpoint_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/accept_endpoint_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/autocomplete_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/autocomplete_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/conditional_proxy.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/conditional_proxy.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/conditional_proxy.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/conditional_proxy.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/constant_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/constant_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/constant_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/constant_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/field_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js
similarity index 96%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/field_autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js
index b2424bebf1b9d..e07db78c4cca9 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/field_autocomplete_component.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js
@@ -17,7 +17,7 @@
* under the License.
*/
import _ from 'lodash';
-import mappings from '../../mappings';
+import mappings from '../../mappings/mappings';
import { ListComponent } from './list_component';
function FieldGenerator(context) {
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/global_only_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/global_only_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/global_only_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/global_only_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/id_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/id_autocomplete_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/id_autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/id_autocomplete_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js
similarity index 96%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index_autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js
index 33e27852caff2..03d67c9e27ee8 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index_autocomplete_component.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js
@@ -17,7 +17,7 @@
* under the License.
*/
import _ from 'lodash';
-import mappings from '../../mappings';
+import mappings from '../../mappings/mappings';
import { ListComponent } from './list_component';
function nonValidIndexType(token) {
return !(token === '_all' || token[0] !== '_');
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/list_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/list_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/list_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/list_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/object_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js
similarity index 98%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/object_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js
index 4db392e60ff83..5cff4a15647ce 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/object_component.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js
@@ -18,7 +18,7 @@
*/
import _ from 'lodash';
-import { SharedComponent } from '.';
+import { SharedComponent } from './index';
/**
* @param constants list of components that represent constant keys
* @param patternsAndWildCards list of components that represent patterns and should be matched only if
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/shared_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/shared_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/shared_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/shared_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/simple_param_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/simple_param_component.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/simple_param_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/simple_param_component.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/template_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js
similarity index 95%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/template_autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js
index 0c00b2f93ee6f..cc62a2f9eeea6 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/template_autocomplete_component.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import mappings from '../../mappings';
+import mappings from '../../mappings/mappings';
import { ListComponent } from './list_component';
export class TemplateAutocompleteComponent extends ListComponent {
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/type_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js
similarity index 96%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/type_autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js
index 4f1c85213b689..ca317fec9e27f 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/type_autocomplete_component.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js
@@ -18,7 +18,7 @@
*/
import _ from 'lodash';
import { ListComponent } from './list_component';
-import mappings from '../../mappings';
+import mappings from '../../mappings/mappings';
function TypeGenerator(context) {
return mappings.getTypes(context.indices);
}
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/url_pattern_matcher.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js
similarity index 99%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/url_pattern_matcher.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js
index 20978c2fbea60..dfae1382bed9b 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/url_pattern_matcher.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js
@@ -23,7 +23,7 @@ import {
AcceptEndpointComponent,
ListComponent,
SimpleParamComponent,
-} from '.';
+} from './index';
/**
* @param parametrizedComponentFactories a dict of the following structure
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/username_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js
similarity index 96%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/username_autocomplete_component.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js
index da3c63b69c610..26b7bd5c48c99 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/username_autocomplete_component.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js
@@ -17,7 +17,7 @@
* under the License.
*/
import _ from 'lodash';
-import mappings from '../../mappings';
+import mappings from '../../mappings/mappings';
import { ListComponent } from './list_component';
function nonValidUsernameType(token) {
return token[0] === '_';
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/engine.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/engine.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/engine.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/engine.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/url_params.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/url_params.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/url_params.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/url_params.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js
similarity index 97%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js
index e1bed169bb730..bf783b3dfe8ae 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js
@@ -18,7 +18,7 @@
*/
const _ = require('lodash');
-const curl = require('../../src/curl');
+const curl = require('../curl');
import curlTests from './curl_parsing.txt';
describe('CURL', () => {
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.txt b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.txt
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.txt
rename to src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.txt
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/curl.js b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/curl.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/curl.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/curl.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/content_type.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js
similarity index 96%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/content_type.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js
index 224eab7dc925d..acc33e331c9f9 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/content_type.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js
@@ -17,7 +17,7 @@
* under the License.
*/
-import { getContentType } from '../../src/es';
+import { getContentType } from '../es';
const APPLICATION_JSON = 'application/json';
describe('Content type', () => {
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/es.js b/src/legacy/core_plugins/console/public/np_ready/lib/es/es.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/es.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/es/es.js
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/kb.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js
similarity index 95%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/kb.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js
index 1618573f911ed..ad29f9808a6c2 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/kb.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js
@@ -18,14 +18,11 @@
*/
import _ from 'lodash';
-import { populateContext } from '../../src/autocomplete/engine';
-
-import './setup_mocks';
-import 'brace';
-import 'brace/mode/javascript';
-import 'brace/mode/json';
-const kb = require('../../src/kb');
-const mappings = require('../../src/mappings');
+import { populateContext } from '../../autocomplete/engine';
+
+import '../../../application/models/sense_editor/sense_editor.test.mocks';
+const kb = require('../../kb');
+const mappings = require('../../mappings/mappings');
describe('Knowledge base', () => {
beforeEach(() => {
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/kb/api.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/api.js
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/src/kb/api.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/api.js
diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js
new file mode 100644
index 0000000000000..383ebef57da92
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js
@@ -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 * from './kb';
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/kb.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js
similarity index 98%
rename from src/legacy/core_plugins/console/public/quarantined/src/kb.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js
index 6a7edf5bc337f..ffba14fad3f37 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/kb.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js
@@ -24,12 +24,12 @@ import {
ListComponent,
TemplateAutocompleteComponent,
UsernameAutocompleteComponent,
-} from './autocomplete/components';
+} from '../autocomplete/components';
import $ from 'jquery';
import _ from 'lodash';
-import Api from './kb/api';
+import Api from './api';
let ACTIVE_API = new Api();
const isNotAnIndexName = name => name[0] === '_' && name !== '_all';
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/mapping.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js
similarity index 97%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/mapping.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js
index d79f3c50b8373..875a16402e394 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/mapping.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js
@@ -16,11 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-import './setup_mocks';
-import 'brace';
-import 'brace/mode/javascript';
-import 'brace/mode/json';
-const mappings = require('../../src/mappings');
+import '../../../application/models/sense_editor/sense_editor.test.mocks';
+const mappings = require('../mappings');
describe('Mappings', () => {
beforeEach(() => {
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/mappings.js b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js
similarity index 98%
rename from src/legacy/core_plugins/console/public/quarantined/src/mappings.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js
index 69f122a607836..b0acf369260e9 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/mappings.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js
@@ -17,11 +17,11 @@
* under the License.
*/
-import { legacyBackDoorToSettings } from '../../../np_ready/public/application';
+import { legacyBackDoorToSettings } from '../../application';
const $ = require('jquery');
const _ = require('lodash');
-const es = require('./es');
+const es = require('../es/es');
// NOTE: If this value ever changes to be a few seconds or less, it might introduce flakiness
// due to timing issues in our app.js tests.
diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts b/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts
new file mode 100644
index 0000000000000..b56d15e178810
--- /dev/null
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts
@@ -0,0 +1,151 @@
+/*
+ * 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 { CoreEditor, Token } from '../types';
+import { TokenIterator } from './token_iterator';
+
+export const MODE = {
+ REQUEST_START: 2,
+ IN_REQUEST: 4,
+ MULTI_DOC_CUR_DOC_END: 8,
+ REQUEST_END: 16,
+ BETWEEN_REQUESTS: 32,
+};
+
+// eslint-disable-next-line import/no-default-export
+export default class RowParser {
+ constructor(private readonly editor: CoreEditor) {}
+
+ MODE = MODE;
+
+ getRowParseMode(lineNumber = this.editor.getCurrentPosition().lineNumber) {
+ const linesCount = this.editor.getLineCount();
+ if (lineNumber > linesCount || lineNumber < 1) {
+ return MODE.BETWEEN_REQUESTS;
+ }
+ const mode = this.editor.getLineState(lineNumber);
+ if (!mode) {
+ return MODE.BETWEEN_REQUESTS;
+ } // shouldn't really happen
+
+ if (mode !== 'start') {
+ return MODE.IN_REQUEST;
+ }
+ let line = (this.editor.getLineValue(lineNumber) || '').trim();
+ if (!line || line[0] === '#') {
+ return MODE.BETWEEN_REQUESTS;
+ } // empty line or a comment waiting for a new req to start
+
+ if (line.indexOf('}', line.length - 1) >= 0) {
+ // check for a multi doc request (must start a new json doc immediately after this one end.
+ lineNumber++;
+ if (lineNumber < linesCount + 1) {
+ line = (this.editor.getLineValue(lineNumber) || '').trim();
+ if (line.indexOf('{') === 0) {
+ // next line is another doc in a multi doc
+ // eslint-disable-next-line no-bitwise
+ return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST;
+ }
+ }
+ // eslint-disable-next-line no-bitwise
+ return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request
+ }
+
+ // check for single line requests
+ lineNumber++;
+ if (lineNumber >= linesCount + 1) {
+ // eslint-disable-next-line no-bitwise
+ return MODE.REQUEST_START | MODE.REQUEST_END;
+ }
+ line = (this.editor.getLineValue(lineNumber) || '').trim();
+ if (line.indexOf('{') !== 0) {
+ // next line is another request
+ // eslint-disable-next-line no-bitwise
+ return MODE.REQUEST_START | MODE.REQUEST_END;
+ }
+
+ return MODE.REQUEST_START;
+ }
+
+ rowPredicate(lineNumber: number | undefined, editor: CoreEditor, value: any) {
+ const mode = this.getRowParseMode(lineNumber);
+ // eslint-disable-next-line no-bitwise
+ return (mode & value) > 0;
+ }
+
+ isEndRequestRow(row?: number, _e?: CoreEditor) {
+ const editor = _e || this.editor;
+ return this.rowPredicate(row, editor, MODE.REQUEST_END);
+ }
+
+ isRequestEdge(row?: number, _e?: CoreEditor) {
+ const editor = _e || this.editor;
+ // eslint-disable-next-line no-bitwise
+ return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START);
+ }
+
+ isStartRequestRow(row?: number, _e?: CoreEditor) {
+ const editor = _e || this.editor;
+ return this.rowPredicate(row, editor, MODE.REQUEST_START);
+ }
+
+ isInBetweenRequestsRow(row?: number, _e?: CoreEditor) {
+ const editor = _e || this.editor;
+ return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS);
+ }
+
+ isInRequestsRow(row?: number, _e?: CoreEditor) {
+ const editor = _e || this.editor;
+ return this.rowPredicate(row, editor, MODE.IN_REQUEST);
+ }
+
+ isMultiDocDocEndRow(row?: number, _e?: CoreEditor) {
+ const editor = _e || this.editor;
+ return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END);
+ }
+
+ isEmptyToken(tokenOrTokenIter: TokenIterator | Token | null) {
+ const token =
+ tokenOrTokenIter && (tokenOrTokenIter as TokenIterator).getCurrentToken
+ ? (tokenOrTokenIter as TokenIterator).getCurrentToken()
+ : tokenOrTokenIter;
+ return !token || (token as Token).type === 'whitespace';
+ }
+
+ isUrlOrMethodToken(tokenOrTokenIter: TokenIterator | Token) {
+ const t = (tokenOrTokenIter as TokenIterator)?.getCurrentToken() ?? (tokenOrTokenIter as Token);
+ return t && t.type && (t.type === 'method' || t.type.indexOf('url') === 0);
+ }
+
+ nextNonEmptyToken(tokenIter: TokenIterator) {
+ let t = tokenIter.stepForward();
+ while (t && this.isEmptyToken(t)) {
+ t = tokenIter.stepForward();
+ }
+ return t;
+ }
+
+ prevNonEmptyToken(tokenIter: TokenIterator) {
+ let t = tokenIter.stepBackward();
+ // empty rows return null token.
+ while ((t || tokenIter.getCurrentPosition().lineNumber > 1) && this.isEmptyToken(t))
+ t = tokenIter.stepBackward();
+ return t;
+ }
+}
diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/index.ts b/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.test.ts b/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.test.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.test.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.test.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.ts b/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.ts
rename to src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.ts
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js
similarity index 91%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/utils.test.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js
index a139aa47b911f..827beadee0f0b 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils.test.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js
@@ -18,12 +18,25 @@
*/
const _ = require('lodash');
-const utils = require('../../src/utils');
+const utils = require('../utils');
const collapsingTests = require('./utils_string_collapsing.txt');
const expandingTests = require('./utils_string_expanding.txt');
describe('Utils class', () => {
+ describe('collapseLiteralStrings', () => {
+ it('will collapse multiline strings', () => {
+ const multiline = '{ "foo": """bar\nbaz""" }';
+ expect(utils.collapseLiteralStrings(multiline)).toEqual('{ "foo": "bar\\nbaz" }');
+ });
+
+ it('will collapse multiline strings with CRLF endings', () => {
+ const multiline = '{ "foo": """bar\r\nbaz""" }';
+ expect(utils.collapseLiteralStrings(multiline)).toEqual('{ "foo": "bar\\r\\nbaz" }');
+ });
+ });
+
+
_.each(collapsingTests.split(/^=+$/m), function (fixture) {
if (fixture.trim() === '') {
return;
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_collapsing.txt b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_collapsing.txt
similarity index 100%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_collapsing.txt
rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_collapsing.txt
diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_expanding.txt b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt
similarity index 79%
rename from src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_expanding.txt
rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt
index 34bf0f3bc20e7..88467ab3672cd 100644
--- a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_expanding.txt
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt
@@ -40,3 +40,15 @@ Correctly parse with JSON embedded inside values
"content\\\\": """ { "json": "inside\\" ok! 1
" } """
}
+==========
+Correctly handle new lines in triple quotes
+-------------------------------------
+{
+ "query": "\n SELECT * FROM \"TABLE\"\n "
+}
+-------------------------------------
+{
+ "query": """
+ SELECT * FROM "TABLE"
+ """
+}
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/utils.js b/src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts
similarity index 77%
rename from src/legacy/core_plugins/console/public/quarantined/src/utils.js
rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts
index 5b6bd1646c300..a7f59acf1d77b 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/utils.js
+++ b/src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts
@@ -19,52 +19,50 @@
import _ from 'lodash';
-const utils = {};
-
-utils.textFromRequest = function (request) {
+export function textFromRequest(request: any) {
let data = request.data;
if (typeof data !== 'string') {
data = data.join('\n');
}
return request.method + ' ' + request.url + '\n' + data;
-};
+}
-utils.jsonToString = function (data, indent) {
+export function jsonToString(data: any, indent: boolean) {
return JSON.stringify(data, null, indent ? 2 : 0);
-};
+}
-utils.reformatData = function (data, indent) {
+export function formatRequestBodyDoc(data: string[], indent: boolean) {
let changed = false;
const formattedData = [];
for (let i = 0; i < data.length; i++) {
const curDoc = data[i];
try {
- let newDoc = utils.jsonToString(JSON.parse(utils.collapseLiteralStrings(curDoc)), indent ? 2 : 0);
+ let newDoc = jsonToString(JSON.parse(collapseLiteralStrings(curDoc)), indent);
if (indent) {
- newDoc = utils.expandLiteralStrings(newDoc);
+ newDoc = expandLiteralStrings(newDoc);
}
changed = changed || newDoc !== curDoc;
formattedData.push(newDoc);
- }
- catch (e) {
+ } catch (e) {
+ // eslint-disable-next-line no-console
console.log(e);
formattedData.push(curDoc);
}
}
return {
- changed: changed,
- data: formattedData
+ changed,
+ data: formattedData,
};
-};
+}
-utils.collapseLiteralStrings = function (data) {
+export function collapseLiteralStrings(data: any) {
const splitData = data.split(`"""`);
for (let idx = 1; idx < splitData.length - 1; idx += 2) {
splitData[idx] = JSON.stringify(splitData[idx]);
}
return splitData.join('');
-};
+}
/*
The following regex describes global match on:
@@ -81,39 +79,38 @@ utils.collapseLiteralStrings = function (data) {
const LITERAL_STRING_CANDIDATES = /((:[\s\r\n]*)([^\\])"(\\"|[^"\n])*\\?")/g;
-utils.expandLiteralStrings = function (data) {
- return data.replace(LITERAL_STRING_CANDIDATES, function (match, string) {
+export function expandLiteralStrings(data: string) {
+ return data.replace(LITERAL_STRING_CANDIDATES, (match, string) => {
// Expand to triple quotes if there are _any_ slashes
if (string.match(/\\./)) {
const firstDoubleQuoteIdx = string.indexOf('"');
const colonAndAnySpacing = string.slice(0, firstDoubleQuoteIdx);
const rawStringifiedValue = string.slice(firstDoubleQuoteIdx, string.length);
- const jsonValue = JSON.parse(rawStringifiedValue)
- .replace('^\s*\n', '')
- .replace('\n\s*^', '');
+ // Remove one level of JSON stringification
+ const jsonValue = JSON.parse(rawStringifiedValue);
return `${colonAndAnySpacing}"""${jsonValue}"""`;
} else {
return string;
}
});
-};
+}
-utils.extractDeprecationMessages = function (warnings) {
+export function extractDeprecationMessages(warnings: string) {
// pattern for valid warning header
const re = /\d{3} [0-9a-zA-Z!#$%&'*+-.^_`|~]+ \"((?:\t| |!|[\x23-\x5b]|[\x5d-\x7e]|[\x80-\xff]|\\\\|\\")*)\"(?: \"[^"]*\")?/;
// split on any comma that is followed by an even number of quotes
- return _.map(utils.splitOnUnquotedCommaSpace(warnings), function (warning) {
+ return _.map(splitOnUnquotedCommaSpace(warnings), warning => {
const match = re.exec(warning);
// extract the actual warning if there was a match
- return '#! Deprecation: ' + (match !== null ? utils.unescape(match[1]) : warning);
+ return '#! Deprecation: ' + (match !== null ? unescape(match[1]) : warning);
});
-};
+}
-utils.unescape = function (s) {
+export function unescape(s: string) {
return s.replace(/\\\\/g, '\\').replace(/\\"/g, '"');
-};
+}
-utils.splitOnUnquotedCommaSpace = function (s) {
+export function splitOnUnquotedCommaSpace(s: string) {
let quoted = false;
const arr = [];
let buffer = '';
@@ -136,6 +133,4 @@ utils.splitOnUnquotedCommaSpace = function (s) {
}
arr.push(buffer);
return arr;
-};
-
-export default utils;
+}
diff --git a/src/legacy/core_plugins/console/np_ready/public/plugin.ts b/src/legacy/core_plugins/console/public/np_ready/plugin.ts
similarity index 90%
rename from src/legacy/core_plugins/console/np_ready/public/plugin.ts
rename to src/legacy/core_plugins/console/public/np_ready/plugin.ts
index 37758adc98d11..cbe262b124677 100644
--- a/src/legacy/core_plugins/console/np_ready/public/plugin.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/plugin.ts
@@ -20,9 +20,8 @@
import { render, unmountComponentAtNode } from 'react-dom';
import { i18n } from '@kbn/i18n';
-import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
-import { PluginInitializerContext, Plugin, CoreStart, CoreSetup } from '../../../../../core/public';
-import { XPluginSet } from './legacy';
+import { PluginInitializerContext, Plugin, CoreStart, CoreSetup } from 'src/core/public';
+import { XPluginSet } from '../legacy';
export class ConsoleUIPlugin implements Plugin {
// @ts-ignore
@@ -30,7 +29,7 @@ export class ConsoleUIPlugin implements Plugin {
async setup({ notifications }: CoreSetup, pluginSet: XPluginSet) {
const {
- __LEGACY: { I18nContext },
+ __LEGACY: { I18nContext, elasticsearchUrl, category },
dev_tools,
home,
} = pluginSet;
@@ -46,7 +45,7 @@ export class ConsoleUIPlugin implements Plugin {
icon: 'consoleApp',
path: '/app/kibana#/dev_tools/console',
showOnHomePage: true,
- category: FeatureCatalogueCategory.ADMIN,
+ category,
});
dev_tools.register({
@@ -63,6 +62,7 @@ export class ConsoleUIPlugin implements Plugin {
docLinkVersion: ctx.core.docLinks.DOC_LINK_VERSION,
I18nContext,
notifications,
+ elasticsearchUrl,
}),
element
);
diff --git a/src/legacy/core_plugins/console/np_ready/public/services/history.ts b/src/legacy/core_plugins/console/public/np_ready/services/history.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/services/history.ts
rename to src/legacy/core_plugins/console/public/np_ready/services/history.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/services/index.ts b/src/legacy/core_plugins/console/public/np_ready/services/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/services/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/services/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/services/settings.ts b/src/legacy/core_plugins/console/public/np_ready/services/settings.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/services/settings.ts
rename to src/legacy/core_plugins/console/public/np_ready/services/settings.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/services/storage.ts b/src/legacy/core_plugins/console/public/np_ready/services/storage.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/services/storage.ts
rename to src/legacy/core_plugins/console/public/np_ready/services/storage.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/types/common.ts b/src/legacy/core_plugins/console/public/np_ready/types/common.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/types/common.ts
rename to src/legacy/core_plugins/console/public/np_ready/types/common.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/types/core_editor.ts b/src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts
similarity index 62%
rename from src/legacy/core_plugins/console/np_ready/public/types/core_editor.ts
rename to src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts
index fdd2e2639e554..8de4c78333fee 100644
--- a/src/legacy/core_plugins/console/np_ready/public/types/core_editor.ts
+++ b/src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts
@@ -20,6 +20,15 @@
import { TokensProvider } from './tokens_provider';
import { Token } from './token';
+type MarkerRef = any;
+
+export type EditorEvent =
+ | 'tokenizerUpdate'
+ | 'changeCursor'
+ | 'changeScrollTop'
+ | 'change'
+ | 'changeSelection';
+
export interface Position {
/**
* The line number, not zero-indexed.
@@ -95,6 +104,13 @@ export interface CoreEditor {
*/
getValue(): string;
+ /**
+ * Sets the contents of the editor.
+ *
+ * Returns a promise so that callers can wait for re-tokenizing to complete.
+ */
+ setValue(value: string, forceRetokenize: boolean): Promise;
+
/**
* Get the contents of the editor at a specific line.
*/
@@ -120,6 +136,11 @@ export interface CoreEditor {
*/
clearSelection(): void;
+ /**
+ * Returns the {@link Range} for currently selected text
+ */
+ getSelectionRange(): Range;
+
/**
* Move the cursor to the indicated position.
*/
@@ -152,4 +173,83 @@ export interface CoreEditor {
* Get line content between and including the start and end lines provided.
*/
getLines(startLine: number, endLine: number): string[];
+
+ /**
+ * Replace a range in the current buffer with the provided value.
+ */
+ replaceRange(range: Range, value: string): void;
+
+ /**
+ * Return the current line count in the buffer.
+ */
+ getLineCount(): number;
+
+ /**
+ * A legacy mechanism which gives consumers of this interface a chance to wait for
+ * latest tokenization to complete.
+ */
+ waitForLatestTokens(): Promise;
+
+ /**
+ * Mark a range in the current buffer
+ */
+ addMarker(range: Range): MarkerRef;
+
+ /**
+ * Mark a range in the current buffer
+ */
+ removeMarker(ref: MarkerRef): void;
+
+ /**
+ * Get a number that represents the current wrap limit on a line
+ */
+ getWrapLimit(): number;
+
+ /**
+ * Register a listener for predefined editor events
+ */
+ on(event: EditorEvent, listener: () => void): void;
+
+ /**
+ * Unregister a listener for predefined editor events
+ */
+ off(event: EditorEvent, listener: () => void): void;
+
+ /**
+ * Execute a predefined editor command.
+ */
+ execCommand(cmd: string): void;
+
+ /**
+ * Returns a boolean value indicating whether or not the completer UI is currently showing in
+ * the editor
+ */
+ isCompleterActive(): boolean;
+
+ /**
+ * Get the HTML container element for this editor instance
+ */
+ getContainer(): HTMLDivElement;
+
+ /**
+ * Because the core editor should not know about requests, but can know about ranges we still
+ * have this backdoor to update UI in response to request range changes, for example, as the user
+ * moves the cursor around
+ */
+ legacyUpdateUI(opts: any): void;
+
+ /**
+ * A method to for the editor to resize, useful when, for instance, window size changes.
+ */
+ resize(): void;
+
+ /**
+ * Expose a way to set styles on the editor
+ */
+ setStyles(styles: { wrapLines: boolean; fontSize: string }): void;
+
+ /**
+ * Register a keyboard shortcut and provide a function to be called.
+ */
+ registerKeyboardShortcut(opts: { keys: any; fn: () => void; name: string }): void;
}
diff --git a/src/legacy/core_plugins/console/np_ready/public/types/index.ts b/src/legacy/core_plugins/console/public/np_ready/types/index.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/types/index.ts
rename to src/legacy/core_plugins/console/public/np_ready/types/index.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/types/token.ts b/src/legacy/core_plugins/console/public/np_ready/types/token.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/types/token.ts
rename to src/legacy/core_plugins/console/public/np_ready/types/token.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/types/tokens_provider.ts b/src/legacy/core_plugins/console/public/np_ready/types/tokens_provider.ts
similarity index 100%
rename from src/legacy/core_plugins/console/np_ready/public/types/tokens_provider.ts
rename to src/legacy/core_plugins/console/public/np_ready/types/tokens_provider.ts
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/directives/_index.scss b/src/legacy/core_plugins/console/public/quarantined/src/directives/_index.scss
deleted file mode 100644
index 56bd7ed20bda4..0000000000000
--- a/src/legacy/core_plugins/console/public/quarantined/src/directives/_index.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-@import './help';
-@import './history';
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/input.ts b/src/legacy/core_plugins/console/public/quarantined/src/input.ts
deleted file mode 100644
index eb93f8e165cb5..0000000000000
--- a/src/legacy/core_plugins/console/public/quarantined/src/input.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// @ts-ignore
-import Autocomplete from './autocomplete';
-
-import { LegacyEditor } from '../../../np_ready/public/application/models';
-
-// @ts-ignore
-import SenseEditor from './sense_editor/editor';
-import { Position } from '../../../np_ready/public/types';
-
-let input: any;
-export function initializeEditor($el: JQuery, $actionsEl: JQuery) {
- input = new SenseEditor($el);
-
- // Autocomplete should not use any Ace functionality directly
- // so we build a shim here.
- const editorShim = {
- coreEditor: new LegacyEditor(input),
- parser: input.parser,
- execCommand: (cmd: string) => input.execCommand(cmd),
- getCursorPosition: (): Position | null => {
- if (input.selection && input.selection.lead) {
- return {
- lineNumber: input.selection.lead.row + 1,
- column: input.selection.lead.column + 1,
- };
- }
- return null;
- },
- isCompleterActive: () => {
- return Boolean(input.__ace.completer && input.__ace.completer.activated);
- },
- addChangeListener: (fn: any) => input.on('changeSelection', fn),
- removeChangeListener: (fn: any) => input.off('changeSelection', fn),
- };
-
- input.autocomplete = new (Autocomplete as any)(editorShim);
- input.setOptions({
- enableBasicAutocompletion: true,
- });
- input.$blockScrolling = Infinity;
- input.$actions = $actionsEl;
-
- /**
- * Init the editor
- */
- input.focus();
- input.highlightCurrentRequestsAndUpdateActionBar();
-
- return input;
-}
-
-// eslint-disable-next-line
-export default function getInput() {
- return input;
-}
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/editor.js b/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/editor.js
deleted file mode 100644
index 9c34860df35ff..0000000000000
--- a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/editor.js
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-const _ = require('lodash');
-const ace = require('brace');
-const $ = require('jquery');
-const curl = require('../curl');
-const RowParser = require('./row_parser');
-const InputMode = require('./mode/input');
-const utils = require('../utils');
-const es = require('../es');
-const chrome = require('ui/chrome');
-
-const smartResize = require('../smart_resize');
-
-function createInstance($el) {
- const aceEditor = ace.edit($el[0]);
-
- // we must create a custom class for each instance, so that the prototype
- // can be the unique aceEditor it extends
- const CustomSenseEditor = function () {
- };
- CustomSenseEditor.prototype = {};
-
- function bindProp(key) {
- Object.defineProperty(CustomSenseEditor.prototype, key, {
- get: function () {
- return aceEditor[key];
- },
- set: function (val) {
- aceEditor[key] = val;
- }
- });
- }
-
- // iterate all of the accessible properties/method, on the prototype and beyond
- // eslint-disable-next-line guard-for-in
- for (const key in aceEditor) {
- switch (typeof aceEditor[key]) {
- case 'function':
- CustomSenseEditor.prototype[key] = _.bindKey(aceEditor, key);
- break;
- default:
- bindProp(key);
- break;
- }
- }
-
- const editor = new CustomSenseEditor();
- editor.__ace = aceEditor;
- return editor;
-}
-
-export default function SenseEditor($el) {
- const editor = createInstance($el);
- let CURRENT_REQ_RANGE = null;
-
- editor.$el = $el;
- // place holder for an action bar, needs to be set externally.
- editor.$actions = null;
-
- // mixin the RowParser
- editor.parser = new RowParser(editor);
- editor.resize = smartResize(editor);
-
- // dirty check for tokenizer state, uses a lot less cycles
- // than listening for tokenizerUpdate
- const onceDoneTokenizing = function (callback, cancelAlreadyScheduledCalls) {
- const session = editor.getSession();
- let timer = false;
- const checkInterval = 25;
-
- return function () {
- const self = this;
- const args = [].slice.call(arguments, 0);
-
- if (cancelAlreadyScheduledCalls) {
- timer = clearTimeout(timer);
- }
-
- setTimeout(function check() {
- // If the bgTokenizer doesn't exist, we can assume that the underlying editor has been
- // torn down, e.g. by closing the History tab, and we don't need to do anything further.
- if (session.bgTokenizer) {
- // Wait until the bgTokenizer is done running before executing the callback.
- if (session.bgTokenizer.running) {
- timer = setTimeout(check, checkInterval);
- } else {
- callback.apply(self, args);
- }
- }
- });
- };
- };
-
- editor.setShowPrintMargin(false);
- (function (session) {
- session.setMode(new InputMode.Mode());
- session.setFoldStyle('markbeginend');
- session.setTabSize(2);
- session.setUseWrapMode(true);
- }(editor.getSession()));
-
- editor.prevRequestStart = function (rowOrPos) {
- rowOrPos = _.isUndefined(rowOrPos) || rowOrPos === null ? editor.getCursorPosition() : rowOrPos;
-
- let curRow = _.isObject(rowOrPos) ? rowOrPos.row : rowOrPos;
- while (curRow > 0 && !editor.parser.isStartRequestRow(curRow, editor)) curRow--;
-
- return {
- row: curRow,
- column: 0
- };
- };
-
- editor.nextRequestStart = function (rowOrPos) {
- rowOrPos = _.isUndefined(rowOrPos) || rowOrPos === null ? editor.getCursorPosition() : rowOrPos;
- const session = editor.getSession();
- let curRow = _.isObject(rowOrPos) ? rowOrPos.row : rowOrPos;
- const maxLines = session.getLength();
- for (; curRow < maxLines - 1; curRow++) {
- if (editor.parser.isStartRequestRow(curRow, editor)) {
- break;
- }
- }
- return {
- row: curRow,
- column: 0
- };
- };
-
- editor.autoIndent = onceDoneTokenizing(function () {
- editor.getRequestRange(function (reqRange) {
- if (!reqRange) {
- return;
- }
- editor.getRequest(function (parsedReq) {
- if (parsedReq.data && parsedReq.data.length > 0) {
- let indent = parsedReq.data.length === 1; // unindent multi docs by default
- let formattedData = utils.reformatData(parsedReq.data, indent);
- if (!formattedData.changed) {
- // toggle.
- indent = !indent;
- formattedData = utils.reformatData(parsedReq.data, indent);
- }
- parsedReq.data = formattedData.data;
-
- editor.replaceRequestRange(parsedReq, reqRange);
- }
- });
- });
- }, true);
-
- editor.update = function (data, callback) {
- callback = typeof callback === 'function' ? callback : null;
- const session = editor.getSession();
-
- session.setValue(data);
- if (callback) {
- // force update of tokens, but not on this thread to allow for ace rendering.
- setTimeout(function () {
- let i;
- for (i = 0; i < session.getLength(); i++) {
- session.getTokens(i);
- }
- callback();
- });
- }
-
- };
-
- editor.replaceRequestRange = function (newRequest, requestRange) {
- const text = utils.textFromRequest(newRequest);
- if (requestRange) {
- const pos = editor.getCursorPosition();
- editor.getSession().replace(requestRange, text);
- const maxRow = Math.max(requestRange.start.row + text.split('\n').length - 1, 0);
- pos.row = Math.min(pos.row, maxRow);
- editor.moveCursorToPosition(pos);
- // ACE UPGRADE - check if needed - at the moment the above may trigger a selection.
- editor.clearSelection();
- }
- else {
- // just insert where we are
- editor.insert(text);
- }
- };
-
- editor.iterForCurrentLoc = function () {
- const pos = editor.getCursorPosition();
- return editor.iterForPosition(pos.row, pos.column, editor);
- };
-
- editor.iterForPosition = function (row, column) {
- return new (ace.acequire('ace/token_iterator').TokenIterator)(editor.getSession(), row, column);
- };
-
- editor.getRequestRange = onceDoneTokenizing(function (row, cb) {
- if (_.isUndefined(cb)) {
- cb = row;
- row = null;
- }
- if (typeof cb !== 'function') {
- return;
- }
-
- if (editor.parser.isInBetweenRequestsRow(row)) {
- cb(null);
- return;
- }
-
- const reqStart = editor.prevRequestStart(row, editor);
- const reqEnd = editor.nextRequestEnd(reqStart, editor);
- cb(new (ace.acequire('ace/range').Range)(
- reqStart.row, reqStart.column,
- reqEnd.row, reqEnd.column
- ));
- });
-
- editor.getEngulfingRequestsRange = onceDoneTokenizing(function (range, cb) {
- if (_.isUndefined(cb)) {
- cb = range;
- range = null;
- }
-
- range = range || editor.getSelectionRange();
-
- const session = editor.getSession();
- let startRow = range.start.row;
- let endRow = range.end.row;
- const maxLine = Math.max(0, session.getLength() - 1);
-
- // move start row to the previous request start if in body, o.w. forward
- if (editor.parser.isInBetweenRequestsRow(startRow)) {
- //for (; startRow <= endRow; startRow++) {
- // if (editor.parser.isStartRequestRow(startRow)) {
- // break;
- // }
- //}
- }
- else {
- for (; startRow >= 0; startRow--) {
- if (editor.parser.isStartRequestRow(startRow)) {
- break;
- }
- }
- }
-
- if (startRow < 0 || startRow > endRow) {
- cb(null);
- return;
- }
- // move end row to the previous request end if between requests, o.w. walk forward
- if (editor.parser.isInBetweenRequestsRow(endRow)) {
- for (; endRow >= startRow; endRow--) {
- if (editor.parser.isEndRequestRow(endRow)) {
- break;
- }
- }
- }
- else {
-
- for (; endRow <= maxLine; endRow++) {
- if (editor.parser.isEndRequestRow(endRow)) {
- break;
- }
- }
-
- }
-
- if (endRow < startRow || endRow > maxLine) {
- cb(null);
- return;
- }
-
- const endColumn = (session.getLine(endRow) || '').replace(/\s+$/, '').length;
- cb(new (ace.acequire('ace/range').Range)(startRow, 0, endRow, endColumn));
- });
-
-
- editor.getRequestInRange = onceDoneTokenizing(function (range, cb) {
- if (!range) {
- return;
- }
- const request = {
- method: '',
- data: [],
- url: null,
- range: range
- };
-
- const pos = range.start;
- const tokenIter = editor.iterForPosition(pos.row, pos.column, editor);
- let t = tokenIter.getCurrentToken();
- if (editor.parser.isEmptyToken(t)) {
- // if the row starts with some spaces, skip them.
- t = editor.parser.nextNonEmptyToken(tokenIter);
- }
- request.method = t.value;
- t = editor.parser.nextNonEmptyToken(tokenIter);
- if (!t || t.type === 'method') {
- return null;
- }
- request.url = '';
- while (t && t.type && t.type.indexOf('url') === 0) {
- request.url += t.value;
- t = tokenIter.stepForward();
- }
- if (editor.parser.isEmptyToken(t)) {
- // if the url row ends with some spaces, skip them.
- t = editor.parser.nextNonEmptyToken(tokenIter);
- }
-
- let bodyStartRow = (t ? 0 : 1) + tokenIter.getCurrentTokenRow(); // artificially increase end of docs.
- let dataEndPos;
- while (bodyStartRow < range.end.row || (
- bodyStartRow === range.end.row && 0 < range.end.column
- )) {
- dataEndPos = editor.nextDataDocEnd({
- row: bodyStartRow,
- column: 0
- });
- const bodyRange = new (ace.acequire('ace/range').Range)(
- bodyStartRow, 0,
- dataEndPos.row, dataEndPos.column
- );
- const data = editor.getSession().getTextRange(bodyRange);
- request.data.push(data.trim());
- bodyStartRow = dataEndPos.row + 1;
- }
-
- cb(request);
- });
-
- editor.getRequestsInRange = function (range, includeNonRequestBlocks, cb) {
- if (_.isUndefined(includeNonRequestBlocks)) {
- includeNonRequestBlocks = false;
- cb = range;
- range = null;
- } else if (_.isUndefined(cb)) {
- cb = includeNonRequestBlocks;
- includeNonRequestBlocks = false;
- }
-
- function explicitRangeToRequests(requestsRange, tempCb) {
- if (!requestsRange) {
- tempCb([]);
- return;
- }
-
- const startRow = requestsRange.start.row;
- const endRow = requestsRange.end.row;
-
- // move to the next request start (during the second iterations this may not be exactly on a request
- let currentRow = startRow;
- for (; currentRow <= endRow; currentRow++) {
- if (editor.parser.isStartRequestRow(currentRow)) {
- break;
- }
- }
-
- let nonRequestPrefixBlock = null;
- if (includeNonRequestBlocks && currentRow !== startRow) {
- nonRequestPrefixBlock = editor.getSession().getLines(startRow, currentRow - 1).join('\n');
- }
-
- if (currentRow > endRow) {
- tempCb(nonRequestPrefixBlock ? [nonRequestPrefixBlock] : []);
- return;
- }
-
- editor.getRequest(currentRow, function (request) {
- if (!request) {
- return;
- }
- explicitRangeToRequests({
- start: {
- row: request.range.end.row + 1
- },
- end: {
- row: requestsRange.end.row
- }
- },
- function (restOfRequests) {
- restOfRequests.unshift(request);
- if (nonRequestPrefixBlock !== null) {
- restOfRequests.unshift(nonRequestPrefixBlock);
- }
- tempCb(restOfRequests);
- }
- );
- });
- }
-
- editor.getEngulfingRequestsRange(range, function (requestRange) {
- explicitRangeToRequests(requestRange, cb);
- });
- };
-
- editor.getRequest = onceDoneTokenizing(function (row, cb) {
- if (_.isUndefined(cb)) {
- cb = row;
- row = null;
- }
- if (typeof cb !== 'function') {
- return;
- }
- if (editor.parser.isInBetweenRequestsRow(row)) {
- cb(null);
- return;
- }
- editor.getRequestRange(row, function (range) {
- editor.getRequestInRange(range, cb);
- });
- });
-
- editor.moveToPreviousRequestEdge = onceDoneTokenizing(function () {
- const pos = editor.getCursorPosition();
- for (pos.row--; pos.row > 0 && !editor.parser.isRequestEdge(pos.row); pos.row--) {
- // loop for side effects
- }
- editor.moveCursorTo(pos.row, 0);
- });
-
- editor.moveToNextRequestEdge = onceDoneTokenizing(function (moveOnlyIfNotOnEdge) {
- const pos = editor.getCursorPosition();
- const maxRow = editor.getSession().getLength();
- if (!moveOnlyIfNotOnEdge) {
- pos.row++;
- }
- for (; pos.row < maxRow && !editor.parser.isRequestEdge(pos.row); pos.row++) {
- // loop for side effects
- }
- editor.moveCursorTo(pos.row, 0);
- });
-
- editor.nextRequestEnd = function (pos) {
- pos = pos || editor.getCursorPosition();
- const session = editor.getSession();
- let curRow = pos.row;
- const maxLines = session.getLength();
- for (; curRow < maxLines - 1; curRow++) {
- const curRowMode = editor.parser.getRowParseMode(curRow, editor);
- if ((curRowMode & editor.parser.MODE.REQUEST_END) > 0) {
- break;
- }
- if (curRow !== pos.row && (curRowMode & editor.parser.MODE.REQUEST_START) > 0) {
- break;
- }
- }
-
- const column = (session.getLine(curRow) || '').replace(/\s+$/, '').length;
-
- return {
- row: curRow,
- column: column
- };
- };
-
- editor.nextDataDocEnd = function (pos) {
- pos = pos || editor.getCursorPosition();
- const session = editor.getSession();
- let curRow = pos.row;
- const maxLines = session.getLength();
- for (; curRow < maxLines - 1; curRow++) {
- const curRowMode = editor.parser.getRowParseMode(curRow, editor);
- if ((curRowMode & RowParser.REQUEST_END) > 0) {
- break;
- }
- if ((curRowMode & editor.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) {
- break;
- }
- if (curRow !== pos.row && (curRowMode & editor.parser.MODE.REQUEST_START) > 0) {
- break;
- }
- }
-
- const column = (session.getLine(curRow) || '').length;
-
- return {
- row: curRow,
- column: column
- };
- };
-
- // overwrite the actual aceEditor's onPaste method
- const origOnPaste = editor.__ace.onPaste;
- editor.__ace.onPaste = function (text) {
- if (text && curl.detectCURL(text)) {
- editor.handleCURLPaste(text);
- return;
- }
- origOnPaste.call(this, text);
- };
-
- editor.handleCURLPaste = function (text) {
- const curlInput = curl.parseCURL(text);
-
- editor.insert(curlInput);
- };
-
- editor.highlightCurrentRequestsAndUpdateActionBar = onceDoneTokenizing(function () {
- const session = editor.getSession();
- editor.getEngulfingRequestsRange(function (newCurrentReqRange) {
- if (newCurrentReqRange === null && CURRENT_REQ_RANGE === null) {
- return;
- }
- if (newCurrentReqRange !== null && CURRENT_REQ_RANGE !== null &&
- newCurrentReqRange.start.row === CURRENT_REQ_RANGE.start.row &&
- newCurrentReqRange.end.row === CURRENT_REQ_RANGE.end.row
- ) {
- // same request, now see if we are on the first line and update the action bar
- const cursorRow = editor.getCursorPosition().row;
- if (cursorRow === CURRENT_REQ_RANGE.start.row) {
- editor.updateActionsBar();
- }
- return; // nothing to do..
- }
-
- if (CURRENT_REQ_RANGE) {
- session.removeMarker(CURRENT_REQ_RANGE.marker_id);
- }
-
- CURRENT_REQ_RANGE = newCurrentReqRange;
- if (CURRENT_REQ_RANGE) {
- CURRENT_REQ_RANGE.marker_id = session.addMarker(CURRENT_REQ_RANGE, 'ace_snippet-marker', 'fullLine');
- }
- editor.updateActionsBar();
- });
- }, true);
-
- editor.getRequestsAsCURL = function (range, cb) {
- if (_.isUndefined(cb)) {
- cb = range;
- range = null;
- }
-
- if (_.isUndefined(cb)) {
- cb = $.noop;
- }
-
- editor.getRequestsInRange(range, true, function (requests) {
-
- const result = _.map(requests, function requestToCurl(req) {
-
- if (typeof req === 'string') {
- // no request block
- return req;
- }
-
- const esPath = req.url;
- const esMethod = req.method;
- const esData = req.data;
-
- // this is the first url defined in elasticsearch.hosts
- const elasticsearchBaseUrl = chrome.getInjected('elasticsearchUrl');
- const url = es.constructESUrl(elasticsearchBaseUrl, esPath);
-
- let ret = 'curl -X' + esMethod + ' "' + url + '"';
- if (esData && esData.length) {
- ret += ' -H \'Content-Type: application/json\' -d\'\n';
- const dataAsString = utils.collapseLiteralStrings(esData.join('\n'));
- // since Sense doesn't allow single quote json string any single qoute is within a string.
- ret += dataAsString.replace(/'/g, '\\"');
- if (esData.length > 1) {
- ret += '\n';
- } // end with a new line
- ret += '\'';
- }
- return ret;
- });
-
- cb(result.join('\n'));
- });
- };
-
- editor.getSession().on('tokenizerUpdate', function () {
- editor.highlightCurrentRequestsAndUpdateActionBar();
- });
-
- editor.getSession().selection.on('changeCursor', function () {
- editor.highlightCurrentRequestsAndUpdateActionBar();
- });
-
- editor.updateActionsBar = (function () {
- const set = function (top) {
- if (top === null) {
- editor.$actions.css('visibility', 'hidden');
- }
- else {
- editor.$actions.css({
- top: top,
- visibility: 'visible'
- });
- }
- };
-
- const hide = function () {
- set();
- };
-
- return function () {
- if (!editor.$actions) {
- return;
- }
- if (CURRENT_REQ_RANGE) {
- // elements are positioned relative to the editor's container
- // pageY is relative to page, so subtract the offset
- // from pageY to get the new top value
- const offsetFromPage = editor.$el.offset().top;
- const startRow = CURRENT_REQ_RANGE.start.row;
- const startColumn = CURRENT_REQ_RANGE.start.column;
- const session = editor.session;
- const firstLine = session.getLine(startRow);
- const maxLineLength = session.getWrapLimit() - 5;
- const isWrapping = firstLine.length > maxLineLength;
- const getScreenCoords = (row) => editor.renderer.textToScreenCoordinates(row, startColumn).pageY - offsetFromPage;
- const topOfReq = getScreenCoords(startRow);
-
- if (topOfReq >= 0) {
- let offset = 0;
- if (isWrapping) {
- // Try get the line height of the text area in pixels.
- const textArea = editor.$el.find('textArea');
- const hasRoomOnNextLine = session.getLine(startRow + 1).length < maxLineLength;
- if (textArea && hasRoomOnNextLine) {
- // Line height + the number of wraps we have on a line.
- offset += (session.getRowLength(startRow) * textArea.height());
- } else {
- if (startRow > 0) {
- set(getScreenCoords(startRow - 1, startColumn));
- return;
- }
- set(getScreenCoords(startRow + 1, startColumn));
- return;
- }
- }
- set(topOfReq + offset);
- return;
- }
-
- const bottomOfReq = editor.renderer.textToScreenCoordinates(
- CURRENT_REQ_RANGE.end.row,
- CURRENT_REQ_RANGE.end.column
- ).pageY - offsetFromPage;
-
- if (bottomOfReq >= 0) {
- set(0);
- return;
- }
- }
-
- hide();
- };
- }());
-
- editor.getSession().on('changeScrollTop', editor.updateActionsBar);
-
- return editor;
-}
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/row_parser.js b/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/row_parser.js
deleted file mode 100644
index c1bba107de784..0000000000000
--- a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/row_parser.js
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-const MODE = {
- REQUEST_START: 2,
- IN_REQUEST: 4,
- MULTI_DOC_CUR_DOC_END: 8,
- REQUEST_END: 16,
- BETWEEN_REQUESTS: 32
-};
-
-/**
- * The RowParser is still using Ace editor directly for now.
- *
- * This will be cleaned up when we implement the editor interface everywhere
- * in the next pass.
- */
-function RowParser(editor) {
- const defaultEditor = editor;
-
- this.getRowParseMode = function (row) {
- if (row === null || typeof row === 'undefined') {
- row = editor.getCursorPosition().row;
- }
-
- const session = editor.getSession();
- if (row >= session.getLength() || row < 0) {
- return MODE.BETWEEN_REQUESTS;
- }
- const mode = session.getState(row);
- if (!mode) {
- return MODE.BETWEEN_REQUESTS;
- } // shouldn't really happen
-
- if (mode !== 'start') {
- return MODE.IN_REQUEST;
- }
- let line = (session.getLine(row) || '').trim();
- if (!line || line[0] === '#') {
- return MODE.BETWEEN_REQUESTS;
- } // empty line or a comment waiting for a new req to start
-
- if (line.indexOf('}', line.length - 1) >= 0) {
- // check for a multi doc request (must start a new json doc immediately after this one end.
- row++;
- if (row < session.getLength()) {
- line = (session.getLine(row) || '').trim();
- if (line.indexOf('{') === 0) { // next line is another doc in a multi doc
- return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST;
- }
-
- }
- return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request
- }
-
- // check for single line requests
- row++;
- if (row >= session.getLength()) {
- return MODE.REQUEST_START | MODE.REQUEST_END;
- }
- line = (session.getLine(row) || '').trim();
- if (line.indexOf('{') !== 0) { // next line is another request
- return MODE.REQUEST_START | MODE.REQUEST_END;
- }
-
- return MODE.REQUEST_START;
- };
-
- this.rowPredicate = function (row, editor, value) {
- const mode = this.getRowParseMode(row, editor);
- return (mode & value) > 0;
- };
-
- this.isEndRequestRow = function (row, _e) {
- const editor = _e || defaultEditor;
- return this.rowPredicate(row, editor, MODE.REQUEST_END);
- };
-
- this.isRequestEdge = function (row, _e) {
- const editor = _e || defaultEditor;
- return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START);
- };
-
- this.isStartRequestRow = function (row, _e) {
- const editor = _e || defaultEditor;
- return this.rowPredicate(row, editor, MODE.REQUEST_START);
- };
-
- this.isInBetweenRequestsRow = function (row, _e) {
- const editor = _e || defaultEditor;
- return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS);
- };
-
- this.isInRequestsRow = function (row, _e) {
- const editor = _e || defaultEditor;
- return this.rowPredicate(row, editor, MODE.IN_REQUEST);
- };
-
- this.isMultiDocDocEndRow = function (row, _e) {
- const editor = _e || defaultEditor;
- return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END);
- };
-
- this.isEmptyToken = function (tokenOrTokenIter) {
- const token = tokenOrTokenIter && tokenOrTokenIter.getCurrentToken ? tokenOrTokenIter.getCurrentToken() : tokenOrTokenIter;
- return !token || token.type === 'whitespace';
- };
-
- this.isUrlOrMethodToken = function (tokenOrTokenIter) {
- const t = tokenOrTokenIter.getCurrentToken ? tokenOrTokenIter.getCurrentToken() : tokenOrTokenIter;
- return t && t.type && (t.type === 'method' || t.type.indexOf('url') === 0);
- };
-
-
- this.nextNonEmptyToken = function (tokenIter) {
- let t = tokenIter.stepForward();
- while (t && this.isEmptyToken(t)) t = tokenIter.stepForward();
- return t;
- };
-
- this.prevNonEmptyToken = function (tokenIter) {
- let t = tokenIter.stepBackward();
- // empty rows return null token.
- while ((t || tokenIter.getCurrentPosition().lineNumber > 1) && this.isEmptyToken(t)) t = tokenIter.stepBackward();
- return t;
- };
-}
-
-RowParser.prototype.MODE = MODE;
-
-export default RowParser;
diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts
index 9fdc41dfd58e5..481349463fc56 100644
--- a/src/legacy/core_plugins/data/public/index.ts
+++ b/src/legacy/core_plugins/data/public/index.ts
@@ -18,7 +18,7 @@
*/
// /// Define plugin function
-import { DataPlugin as Plugin, DataSetup, DataStart } from './plugin';
+import { DataPlugin as Plugin, DataStart } from './plugin';
export function plugin() {
return new Plugin();
@@ -27,15 +27,9 @@ export function plugin() {
// /// Export types & static code
/** @public types */
-export { DataSetup, DataStart };
+export { DataStart };
-export {
- Field,
- FieldType,
- FieldListInterface,
- IndexPattern,
- IndexPatterns,
-} from './index_patterns';
+export { Field, FieldType, IFieldList, IndexPattern } from './index_patterns';
export { SearchBar, SearchBarProps } from './search';
export {
SavedQueryAttributes,
diff --git a/src/legacy/core_plugins/data/public/index_patterns/index.ts b/src/legacy/core_plugins/data/public/index_patterns/index.ts
index 74981165f3e47..96995c10e5469 100644
--- a/src/legacy/core_plugins/data/public/index_patterns/index.ts
+++ b/src/legacy/core_plugins/data/public/index_patterns/index.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { IFieldType, IIndexPattern, indexPatterns } from '../../../../../plugins/data/public';
+import { IFieldType, indexPatterns } from '../../../../../plugins/data/public';
const getFromSavedObject = indexPatterns.getFromSavedObject;
const getRoutes = indexPatterns.getRoutes;
@@ -25,13 +25,9 @@ const flattenHitWrapper = indexPatterns.flattenHitWrapper;
export { getFromSavedObject, getRoutes, flattenHitWrapper };
export { IFieldType as FieldType };
-export { IIndexPattern as StaticIndexPattern };
export {
Field,
- FieldListInterface,
+ IFieldList,
IndexPattern,
- IndexPatterns,
- IndexPatternsStart,
- IndexPatternsSetup,
- IndexPatternsService,
+ IndexPatternsContract,
} from '../../../../../plugins/data/public';
diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts
index b1d838aed992d..a6646ea338c93 100644
--- a/src/legacy/core_plugins/data/public/legacy.ts
+++ b/src/legacy/core_plugins/data/public/legacy.ts
@@ -43,5 +43,4 @@ export const setup = dataPlugin.setup(npSetup.core);
export const start = dataPlugin.start(npStart.core, {
data: npStart.plugins.data,
- uiActions: npSetup.plugins.uiActions,
});
diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts
index 6cce91a5a25b5..a4fdfd7482f74 100644
--- a/src/legacy/core_plugins/data/public/plugin.ts
+++ b/src/legacy/core_plugins/data/public/plugin.ts
@@ -19,29 +19,15 @@
import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
import { createSearchBar, StatetfulSearchBarProps } from './search';
-import { IndexPatternsService, IndexPatternsSetup, IndexPatternsStart } from './index_patterns';
import { Storage, IStorageWrapper } from '../../../../../src/plugins/kibana_utils/public';
import { DataPublicPluginStart } from '../../../../plugins/data/public';
import { initLegacyModule } from './shim/legacy_module';
-import { IUiActionsSetup } from '../../../../plugins/ui_actions/public';
-import {
- createFilterAction,
- GLOBAL_APPLY_FILTER_ACTION,
-} from './filter/action/apply_filter_action';
-import { APPLY_FILTER_TRIGGER } from '../../../../plugins/embeddable/public';
+
+// eslint-disable-next-line @kbn/eslint/no-restricted-paths
+import { setFieldFormats } from '../../../../plugins/data/public/services';
export interface DataPluginStartDependencies {
data: DataPublicPluginStart;
- uiActions: IUiActionsSetup;
-}
-
-/**
- * Interface for this plugin's returned `setup` contract.
- *
- * @public
- */
-export interface DataSetup {
- indexPatterns: IndexPatternsSetup;
}
/**
@@ -50,7 +36,6 @@ export interface DataSetup {
* @public
*/
export interface DataStart {
- indexPatterns: IndexPatternsStart;
ui: {
SearchBar: React.ComponentType;
};
@@ -68,34 +53,17 @@ export interface DataStart {
* or static code.
*/
-export class DataPlugin implements Plugin {
- private readonly indexPatterns: IndexPatternsService = new IndexPatternsService();
-
- private setupApi!: DataSetup;
+export class DataPlugin implements Plugin {
private storage!: IStorageWrapper;
- public setup(core: CoreSetup): DataSetup {
+ public setup(core: CoreSetup) {
this.storage = new Storage(window.localStorage);
-
- this.setupApi = {
- indexPatterns: this.indexPatterns.setup(),
- };
-
- return this.setupApi;
}
- public start(core: CoreStart, { data, uiActions }: DataPluginStartDependencies): DataStart {
- const { uiSettings, http, notifications, savedObjects } = core;
-
- const indexPatternsService = this.indexPatterns.start({
- uiSettings,
- savedObjectsClient: savedObjects.client,
- http,
- notifications,
- fieldFormats: data.fieldFormats,
- });
-
- initLegacyModule(indexPatternsService.indexPatterns);
+ public start(core: CoreStart, { data }: DataPluginStartDependencies): DataStart {
+ // This is required for when Angular code uses Field and FieldList.
+ setFieldFormats(data.fieldFormats);
+ initLegacyModule(data.indexPatterns);
const SearchBar = createSearchBar({
core,
@@ -103,27 +71,12 @@ export class DataPlugin implements Plugin {
+export const initLegacyModule = once((indexPatterns: IndexPatternsContract): void => {
uiModules.get('kibana/index_patterns').value('indexPatterns', indexPatterns);
});
diff --git a/src/legacy/core_plugins/input_control_vis/public/components/editor/controls_tab.js b/src/legacy/core_plugins/input_control_vis/public/components/editor/controls_tab.js
index 6d4ce31d453cc..d5f58236027a9 100644
--- a/src/legacy/core_plugins/input_control_vis/public/components/editor/controls_tab.js
+++ b/src/legacy/core_plugins/input_control_vis/public/components/editor/controls_tab.js
@@ -23,7 +23,7 @@ import { ControlEditor } from './control_editor';
import { addControl, moveControl, newControl, removeControl, setControl } from '../../editor_utils';
import { getLineageMap, getParentCandidates } from '../../lineage';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
-import { start as data } from '../../../../../core_plugins/data/public/legacy';
+import { npStart } from 'ui/new_platform';
import {
EuiButton,
@@ -41,7 +41,7 @@ class ControlsTabUi extends Component {
}
getIndexPattern = async (indexPatternId) => {
- return await data.indexPatterns.indexPatterns.get(indexPatternId);
+ return await npStart.plugins.data.indexPatterns.get(indexPatternId);
}
onChange = value => this.props.setValue('controls', value)
diff --git a/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.js b/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.js
index 86fe6db9b0778..e1dadff4a9ae7 100644
--- a/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.js
+++ b/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.js
@@ -28,7 +28,6 @@ import { createSearchSource } from './create_search_source';
import { i18n } from '@kbn/i18n';
import { npStart } from 'ui/new_platform';
import chrome from 'ui/chrome';
-import { start as data } from '../../../../core_plugins/data/public/legacy';
function getEscapedQuery(query = '') {
// https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#_standard_operators
@@ -173,7 +172,7 @@ class ListControl extends Control {
export async function listControlFactory(controlParams, useTimeFilter, SearchSource) {
let indexPattern;
try {
- indexPattern = await data.indexPatterns.indexPatterns.get(controlParams.indexPattern);
+ indexPattern = await npStart.plugins.data.indexPatterns.get(controlParams.indexPattern);
// dynamic options are only allowed on String fields but the setting defaults to true so it could
// be enabled for non-string fields (since UI input is hidden for non-string fields).
diff --git a/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.test.js b/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.test.js
index b40a9f8e6efd4..c5f6de1c53097 100644
--- a/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.test.js
+++ b/src/legacy/core_plugins/input_control_vis/public/control/list_control_factory.test.js
@@ -40,27 +40,20 @@ jest.mock('ui/new_platform', () => ({
getAppFilters: jest.fn().mockImplementation(() => ([])),
getGlobalFilters: jest.fn().mockImplementation(() => ([])),
}
+ },
+ indexPatterns: {
+ get: () => ({
+ fields: { getByName: name => {
+ const fields = { myField: { name: 'myField' } };
+ return fields[name];
+ } }
+ }),
}
}
},
},
}));
-jest.mock('../../../../core_plugins/data/public/legacy', () => ({
- start: {
- indexPatterns: {
- indexPatterns: {
- get: () => ({
- fields: { getByName: name => {
- const fields = { myField: { name: 'myField' } };
- return fields[name];
- } }
- }),
- }
- },
- }
-}));
-
chrome.getInjected.mockImplementation((key) => {
switch(key) {
case 'autocompleteTimeout': return 1000;
diff --git a/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.js b/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.js
index 2a05a1224aab9..d2b1aff78ac2b 100644
--- a/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.js
+++ b/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.js
@@ -26,7 +26,6 @@ import {
import { RangeFilterManager } from './filter_manager/range_filter_manager';
import { createSearchSource } from './create_search_source';
import { i18n } from '@kbn/i18n';
-import { start as data } from '../../../../core_plugins/data/public/legacy';
import { npStart } from 'ui/new_platform';
const minMaxAgg = (field) => {
@@ -103,7 +102,7 @@ class RangeControl extends Control {
export async function rangeControlFactory(controlParams, useTimeFilter, SearchSource) {
let indexPattern;
try {
- indexPattern = await data.indexPatterns.indexPatterns.get(controlParams.indexPattern);
+ indexPattern = await npStart.plugins.data.indexPatterns.get(controlParams.indexPattern);
} catch (err) {
// ignore not found error and return control so it can be displayed in disabled state.
}
diff --git a/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.test.js b/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.test.js
index 3e6d6a49a1118..eaefcda4140fc 100644
--- a/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.test.js
+++ b/src/legacy/core_plugins/input_control_vis/public/control/range_control_factory.test.js
@@ -48,27 +48,20 @@ jest.mock('ui/new_platform', () => ({
getAppFilters: jest.fn().mockImplementation(() => ([])),
getGlobalFilters: jest.fn().mockImplementation(() => ([])),
}
+ },
+ indexPatterns: {
+ get: () => ({
+ fields: { getByName: name => {
+ const fields = { myNumberField: { name: 'myNumberField' } };
+ return fields[name];
+ }
+ } }),
}
}
},
},
}));
-jest.mock('../../../../core_plugins/data/public/legacy', () => ({
- start: {
- indexPatterns: {
- indexPatterns: {
- get: () => ({
- fields: { getByName: name => {
- const fields = { myNumberField: { name: 'myNumberField' } };
- return fields[name];
- }
- } }),
- }
- },
- }
-}));
-
describe('fetch', () => {
const controlParams = {
id: '1',
diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js
index 33e820a5300c6..659ca36d84090 100644
--- a/src/legacy/core_plugins/kibana/index.js
+++ b/src/legacy/core_plugins/kibana/index.js
@@ -62,6 +62,7 @@ export default function (kibana) {
hacks: [
'plugins/kibana/discover',
'plugins/kibana/dev_tools',
+ 'plugins/kibana/visualize',
],
savedObjectTypes: [
'plugins/kibana/visualize/saved_visualizations/saved_visualization_register',
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap
index 07e4173d5323f..8410040a0100d 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap
+++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap
@@ -193,78 +193,160 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = `
textComponent={Symbol(react.fragment)}
>
-
-
-
-
-
-
- This dashboard is empty. Let’s fill it up!
-
-
-
- Click the
-
-
- Add
-
-
- button in the menu bar above to add a visualization to the dashboard.
-
-
-
-
- visit the Visualize app
-
,
+ "maxWidth": "36em",
}
}
>
- If you haven't set up any visualizations yet,
-
- visit the Visualize app
-
- to create your first visualization
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This dashboard is empty. Let’s fill it up!
+
+
+
+
+
+
+
+
+
+ Click the
+
+
+ Add
+
+
+ button in the menu bar above to add a visualization to the dashboard.
+
+
+
+
+
+
+
+
+
+
+ visit the Visualize app
+ ,
+ }
+ }
+ >
+ If you haven't set up any visualizations yet,
+
+ visit the Visualize app
+
+ to create your first visualization
+
+
+
+
+
+
+
+
+
+
+
@@ -464,51 +546,119 @@ exports[`DashboardEmptyScreen renders correctly without visualize paragraph 1`]
textComponent={Symbol(react.fragment)}
>
-
-
-
-
-
-
- This dashboard is empty. Let’s fill it up!
-
-
-
- Click the
-
-
- Edit
-
-
- button in the menu bar above to start working on your new dashboard.
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This dashboard is empty. Let’s fill it up!
+
+
+
+
+
+
+
+
+
+ Click the
+
+
+ Edit
+
+
+ button in the menu bar above to start working on your new dashboard.
+
+
+
+
+
+
+
+
+
+
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx
index a4604d17ddecd..69bdcf59bb227 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx
@@ -18,7 +18,9 @@
*/
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { DashboardEmptyScreen, Props } from '../dashboard_empty_screen';
+import { DashboardEmptyScreen, DashboardEmptyScreenProps } from '../dashboard_empty_screen';
+// @ts-ignore
+import { findTestSubject } from '@elastic/eui/lib/test';
describe('DashboardEmptyScreen', () => {
const defaultProps = {
@@ -26,7 +28,7 @@ describe('DashboardEmptyScreen', () => {
onLinkClick: jest.fn(),
};
- function mountComponent(props?: Props) {
+ function mountComponent(props?: DashboardEmptyScreenProps) {
const compProps = props || defaultProps;
const comp = mountWithIntl( );
return comp;
@@ -35,14 +37,14 @@ describe('DashboardEmptyScreen', () => {
test('renders correctly with visualize paragraph', () => {
const component = mountComponent();
expect(component).toMatchSnapshot();
- const paragraph = component.find('.linkToVisualizeParagraph');
+ const paragraph = findTestSubject(component, 'linkToVisualizeParagraph');
expect(paragraph.length).toBe(1);
});
test('renders correctly without visualize paragraph', () => {
const component = mountComponent({ ...defaultProps, ...{ showLinkToVisualize: false } });
expect(component).toMatchSnapshot();
- const paragraph = component.find('.linkToVisualizeParagraph');
+ const paragraph = findTestSubject(component, 'linkToVisualizeParagraph');
expect(paragraph.length).toBe(0);
});
});
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss b/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss
index 14c35759d70a9..d9eadf6c0e37d 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss
+++ b/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss
@@ -6,9 +6,5 @@
.dshStartScreen {
text-align: center;
- padding: $euiSize;
-
- > * {
- max-width: 36em !important;
- }
+ padding: $euiSizeS;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/application.ts
index 42ecc0fea5f07..ef1bcab589c4a 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/application.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/application.ts
@@ -47,7 +47,6 @@ import {
// @ts-ignore
import { initDashboardApp } from './legacy_app';
-import { DataStart, IndexPatterns } from '../../../data/public';
import { IEmbeddableStart } from '../../../../../plugins/embeddable/public';
import { NavigationStart } from '../../../navigation/public';
import { DataPublicPluginStart as NpDataStart } from '../../../../../plugins/data/public';
@@ -55,8 +54,6 @@ import { SharePluginStart } from '../../../../../plugins/share/public';
export interface RenderDeps {
core: LegacyCoreStart;
- indexPatterns: IndexPatterns;
- dataStart: DataStart;
npDataStart: NpDataStart;
navigation: NavigationStart;
savedObjectsClient: SavedObjectsClientContract;
@@ -134,7 +131,6 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav
'app/dashboard/State',
'app/dashboard/ConfirmModal',
'app/dashboard/icon',
- 'app/dashboard/emptyScreen',
]);
return dashboardAngularModule;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
index 4f41ab5d4fad6..3cf8932958b6d 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
@@ -35,7 +35,7 @@
-->
-
-
{{screenTitle}}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
index dcedb2a166fcc..04a8e68276fc2 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
@@ -118,6 +118,7 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) {
AppStateClass: AppState,
config,
confirmModal,
+ indexPatterns: deps.npDataStart.indexPatterns,
...deps,
}),
};
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index b5a6db912bdf0..3b336ebfc11fe 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -21,9 +21,10 @@ import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import React from 'react';
import angular from 'angular';
-import { uniq } from 'lodash';
+import { uniq, noop } from 'lodash';
import { Subscription } from 'rxjs';
+import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen';
import {
subscribeWithScope,
@@ -39,9 +40,7 @@ import {
unhashUrl,
} from './legacy_imports';
import { FilterStateManager, IndexPattern } from '../../../data/public';
-import { Query, SavedQuery, IndexPatterns } from '../../../../../plugins/data/public';
-
-import './dashboard_empty_screen_directive';
+import { Query, SavedQuery, IndexPatternsContract } from '../../../../../plugins/data/public';
import {
DashboardContainer,
@@ -78,7 +77,7 @@ export interface DashboardAppControllerDependencies extends RenderDeps {
$routeParams: any;
getAppState: any;
globalState: State;
- indexPatterns: IndexPatterns;
+ indexPatterns: IndexPatternsContract;
dashboardConfig: any;
kbnUrl: KbnUrl;
AppStateClass: TAppStateClass;
@@ -143,6 +142,16 @@ export class DashboardAppController {
}
$scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean;
+ $scope.getShouldShowEditHelp = () =>
+ !dashboardStateManager.getPanels().length &&
+ dashboardStateManager.getIsEditMode() &&
+ !dashboardConfig.getHideWriteControls();
+
+ $scope.getShouldShowViewHelp = () =>
+ !dashboardStateManager.getPanels().length &&
+ dashboardStateManager.getIsViewMode() &&
+ !dashboardConfig.getHideWriteControls();
+
const updateIndexPatterns = (container?: DashboardContainer) => {
if (!container || isErrorEmbeddable(container)) {
return;
@@ -171,6 +180,17 @@ export class DashboardAppController {
}
};
+ const getEmptyScreenProps = (shouldShowEditHelp: boolean): DashboardEmptyScreenProps => {
+ const emptyScreenProps: DashboardEmptyScreenProps = {
+ onLinkClick: shouldShowEditHelp ? $scope.showAddPanel : $scope.enterEditMode,
+ showLinkToVisualize: shouldShowEditHelp,
+ };
+ if (shouldShowEditHelp) {
+ emptyScreenProps.onVisualizeClick = noop;
+ }
+ return emptyScreenProps;
+ };
+
const getDashboardInput = (): DashboardContainerInput => {
const embeddablesMap: {
[key: string]: DashboardPanelState;
@@ -182,6 +202,8 @@ export class DashboardAppController {
if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) {
expandedPanelId = dashboardContainer.getInput().expandedPanelId;
}
+ const shouldShowEditHelp = $scope.getShouldShowEditHelp();
+ const shouldShowViewHelp = $scope.getShouldShowViewHelp();
return {
id: dashboardStateManager.savedDashboard.id || '',
filters: queryFilter.getFilters(),
@@ -194,6 +216,7 @@ export class DashboardAppController {
viewMode: dashboardStateManager.getViewMode(),
panels: embeddablesMap,
isFullScreenMode: dashboardStateManager.getFullScreenMode(),
+ isEmptyState: shouldShowEditHelp || shouldShowViewHelp,
useMargins: dashboardStateManager.getUseMargins(),
lastReloadRequestTime,
title: dashboardStateManager.getTitle(),
@@ -234,6 +257,15 @@ export class DashboardAppController {
if (!isErrorEmbeddable(container)) {
dashboardContainer = container;
+ dashboardContainer.renderEmpty = () => {
+ const shouldShowEditHelp = $scope.getShouldShowEditHelp();
+ const shouldShowViewHelp = $scope.getShouldShowViewHelp();
+ const isEmptyState = shouldShowEditHelp || shouldShowViewHelp;
+ return isEmptyState ? (
+
+ ) : null;
+ };
+
updateIndexPatterns(dashboardContainer);
outputSubscription = dashboardContainer.getOutput$().subscribe(() => {
@@ -334,15 +366,6 @@ export class DashboardAppController {
updateBreadcrumbs();
dashboardStateManager.registerChangeListener(updateBreadcrumbs);
- $scope.getShouldShowEditHelp = () =>
- !dashboardStateManager.getPanels().length &&
- dashboardStateManager.getIsEditMode() &&
- !dashboardConfig.getHideWriteControls();
- $scope.getShouldShowViewHelp = () =>
- !dashboardStateManager.getPanels().length &&
- dashboardStateManager.getIsViewMode() &&
- !dashboardConfig.getHideWriteControls();
-
const getChangesFromAppStateForContainerState = () => {
const appStateDashboardInput = getDashboardInput();
if (!dashboardContainer || isErrorEmbeddable(dashboardContainer)) {
@@ -729,6 +752,8 @@ export class DashboardAppController {
}
};
+ navActions[TopNavIds.VISUALIZE] = async () => {};
+
navActions[TopNavIds.OPTIONS] = anchorElement => {
showOptionsPopover({
anchorElement,
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx
index d5a4e6e6a325d..234228ba4166a 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx
@@ -18,29 +18,43 @@
*/
import React from 'react';
import { I18nProvider, FormattedMessage } from '@kbn/i18n/react';
-import { EuiIcon, EuiLink } from '@elastic/eui';
+import {
+ EuiIcon,
+ EuiLink,
+ EuiSpacer,
+ EuiPageContent,
+ EuiPageBody,
+ EuiPage,
+ EuiText,
+} from '@elastic/eui';
import * as constants from './dashboard_empty_screen_constants';
-export interface Props {
+export interface DashboardEmptyScreenProps {
showLinkToVisualize: boolean;
onLinkClick: () => void;
+ onVisualizeClick?: () => void;
}
-export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props) {
+export function DashboardEmptyScreen({
+ showLinkToVisualize,
+ onLinkClick,
+}: DashboardEmptyScreenProps) {
const linkToVisualizeParagraph = (
-
-
- {constants.visualizeAppLinkTest}
-
- ),
- }}
- />
-
+
+
+
+ {constants.visualizeAppLinkTest}
+
+ ),
+ }}
+ />
+
+
);
const paragraph = (
description1: string,
@@ -50,15 +64,15 @@ export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props
dataTestSubj?: string
) => {
return (
-
-
+
+
{description1}
{linkText}
{description2}
-
-
+
+
);
};
const addVisualizationParagraph = (
@@ -70,6 +84,7 @@ export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props
constants.addVisualizationLinkAriaLabel,
'emptyDashboardAddPanelButton'
)}
+
{linkToVisualizeParagraph}
);
@@ -81,11 +96,19 @@ export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props
);
return (
-
-
- {constants.fillDashboardTitle}
- {showLinkToVisualize ? addVisualizationParagraph : enterEditModeParagraph}
-
+
+
+
+
+
+
+ {constants.fillDashboardTitle}
+
+
+ {showLinkToVisualize ? addVisualizationParagraph : enterEditModeParagraph}
+
+
+
);
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_app.js b/src/legacy/core_plugins/kibana/public/dashboard/legacy_app.js
index c7f2adb4b875b..7d60b80b59620 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_app.js
@@ -119,7 +119,7 @@ export function initDashboardApp(app, deps) {
},
resolve: {
dash: function ($rootScope, $route, redirectWhenMissing, kbnUrl) {
- return ensureDefaultIndexPattern(deps.core, deps.dataStart, $rootScope, kbnUrl).then(() => {
+ return ensureDefaultIndexPattern(deps.core, deps.npDataStart, $rootScope, kbnUrl).then(() => {
const savedObjectsClient = deps.savedObjectsClient;
const title = $route.current.params.title;
if (title) {
@@ -154,7 +154,7 @@ export function initDashboardApp(app, deps) {
requireUICapability: 'dashboard.createNew',
resolve: {
dash: function (redirectWhenMissing, $rootScope, kbnUrl) {
- return ensureDefaultIndexPattern(deps.core, deps.dataStart, $rootScope, kbnUrl)
+ return ensureDefaultIndexPattern(deps.core, deps.npDataStart, $rootScope, kbnUrl)
.then(() => {
return deps.savedDashboards.get();
})
@@ -174,7 +174,7 @@ export function initDashboardApp(app, deps) {
dash: function ($rootScope, $route, redirectWhenMissing, kbnUrl, AppState) {
const id = $route.current.params.id;
- return ensureDefaultIndexPattern(deps.core, deps.dataStart, $rootScope, kbnUrl)
+ return ensureDefaultIndexPattern(deps.core, deps.npDataStart, $rootScope, kbnUrl)
.then(() => {
return deps.savedDashboards.get(id);
})
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
index 7c3c389330887..b0f09f0cf9745 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
@@ -63,6 +63,6 @@ export { confirmModalFactory } from 'ui/modals/confirm_modal';
export { configureAppAngularModule } from 'ui/legacy_compat';
export { stateMonitorFactory, StateMonitor } from 'ui/state_management/state_monitor_factory';
export { ensureDefaultIndexPattern } from 'ui/legacy_compat';
-export { unhashUrl } from 'ui/state_management/state_hashing';
+export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
export { IInjector } from 'ui/chrome';
export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
index cb0980c914983..d2b45fde4727e 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
@@ -64,7 +64,6 @@ export interface DashboardPluginSetupDependencies {
export class DashboardPlugin implements Plugin {
private startDependencies: {
- dataStart: DataStart;
npDataStart: NpDataStart;
savedObjectsClient: SavedObjectsClientContract;
embeddables: IEmbeddableStart;
@@ -84,7 +83,6 @@ export class DashboardPlugin implements Plugin {
throw new Error('not started yet');
}
const {
- dataStart,
savedObjectsClient,
embeddables,
navigation,
@@ -96,10 +94,8 @@ export class DashboardPlugin implements Plugin {
core: contextCore as LegacyCoreStart,
...angularDependencies,
navigation,
- dataStart,
share,
npDataStart,
- indexPatterns: dataStart.indexPatterns.indexPatterns,
savedObjectsClient,
chrome: contextCore.chrome,
addBasePath: contextCore.http.basePath.prepend,
@@ -136,7 +132,6 @@ export class DashboardPlugin implements Plugin {
{ data: dataStart, embeddables, navigation, npData, share }: DashboardPluginStartDependencies
) {
this.startDependencies = {
- dataStart,
npDataStart: npData,
savedObjectsClient,
embeddables,
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts b/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts
index 9df86f2ca3cce..c67d6891c18e7 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts
@@ -26,4 +26,5 @@ export const TopNavIds = {
ENTER_EDIT_MODE: 'enterEditMode',
CLONE: 'clone',
FULL_SCREEN: 'fullScreenMode',
+ VISUALIZE: 'visualize',
};
diff --git a/src/legacy/core_plugins/kibana/public/discover/_discover.scss b/src/legacy/core_plugins/kibana/public/discover/_discover.scss
index 12cac1c89275b..0da28e41579ae 100644
--- a/src/legacy/core_plugins/kibana/public/discover/_discover.scss
+++ b/src/legacy/core_plugins/kibana/public/discover/_discover.scss
@@ -1,5 +1,3 @@
-@import 'node_modules/@elastic/eui/src/components/panel/mixins';
-
discover-app {
flex-grow: 1;
@@ -37,7 +35,7 @@ discover-app {
z-index: 1;
}
-@include euiPanel('dscWrapper__content');
+@include euiPanel('.dscWrapper__content');
.dscWrapper__content {
padding-top: $euiSizeXS;
@@ -213,7 +211,6 @@ discover-app {
}
.dscResults {
-
h3 {
margin: -20px 0 10px 0;
text-align: center;
diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/context/api/context.ts b/src/legacy/core_plugins/kibana/public/discover/angular/context/api/context.ts
index 674f5616faa30..fd71b7c49e837 100644
--- a/src/legacy/core_plugins/kibana/public/discover/angular/context/api/context.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/angular/context/api/context.ts
@@ -17,14 +17,14 @@
* under the License.
*/
-import { IndexPatterns, IndexPattern, SearchSource } from '../../../kibana_services';
+import { IndexPattern, SearchSource } from '../../../kibana_services';
import { reverseSortDir, SortDirection } from './utils/sorting';
import { extractNanos, convertIsoToMillis } from './utils/date_conversion';
import { fetchHitsInInterval } from './utils/fetch_hits_in_interval';
import { generateIntervals } from './utils/generate_intervals';
import { getEsQuerySearchAfter } from './utils/get_es_query_search_after';
import { getEsQuerySort } from './utils/get_es_query_sort';
-import { esFilters } from '../../../../../../../../plugins/data/public';
+import { esFilters, IndexPatternsContract } from '../../../../../../../../plugins/data/public';
export type SurrDocType = 'successors' | 'predecessors';
export interface EsHitRecord {
@@ -39,7 +39,7 @@ const DAY_MILLIS = 24 * 60 * 60 * 1000;
// look from 1 day up to 10000 days into the past and future
const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map(days => days * DAY_MILLIS);
-function fetchContextProvider(indexPatterns: IndexPatterns) {
+function fetchContextProvider(indexPatterns: IndexPatternsContract) {
return {
fetchSurroundingDocs,
};
diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
index 7abb7166aa902..ce1419cd637b9 100644
--- a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
+++ b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
@@ -65,7 +65,6 @@ const {
data,
docTitle,
filterManager,
- State,
share,
timefilter,
toastNotifications,
@@ -73,13 +72,12 @@ const {
} = getServices();
import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs';
-import { start as dataLP } from '../../../../data/public/legacy';
import { generateFilters } from '../../../../../../plugins/data/public';
import { getIndexPatternId } from '../helpers/get_index_pattern_id';
import { registerTimefilterWithGlobalStateFactory } from '../../../../../ui/public/timefilter/setup_router';
import { FilterStateManager } from '../../../../data/public/filter/filter_manager';
-const { savedQueryService } = data.query.savedQueries;
+const { getSavedQuery } = data.query.savedQueries;
const fetchStatuses = {
UNINITIALIZED: 'uninitialized',
@@ -122,10 +120,10 @@ app.config($routeProvider => {
template: indexTemplate,
reloadOnSearch: false,
resolve: {
- savedObjects: function (redirectWhenMissing, $route, kbnUrl, Promise, $rootScope) {
- const indexPatterns = dataLP.indexPatterns.indexPatterns;
+ savedObjects: function (redirectWhenMissing, $route, kbnUrl, Promise, $rootScope, State) {
+ const indexPatterns = getServices().indexPatterns;
const savedSearchId = $route.current.params.id;
- return ensureDefaultIndexPattern(core, dataLP, $rootScope, kbnUrl).then(() => {
+ return ensureDefaultIndexPattern(core, getServices().data, $rootScope, kbnUrl).then(() => {
return Promise.props({
ip: indexPatterns.getCache().then((indexPatternList) => {
/**
@@ -138,7 +136,6 @@ app.config($routeProvider => {
* @type {State}
*/
const state = new State('_a', {});
-
const id = getIndexPatternId(state.index, indexPatternList, uiSettings.get('defaultIndex'));
state.destroy();
return Promise.props({
@@ -422,7 +419,7 @@ function discoverController(
};
const getFieldCounts = async () => {
- // the field counts aren't set until we have the dataLP back,
+ // the field counts aren't set until we have the data back,
// so we wait for the fetch to be done before proceeding
if ($scope.fetchStatus === fetchStatuses.COMPLETE) {
return $scope.fieldCounts;
@@ -578,7 +575,7 @@ function discoverController(
if (!angular.equals(sort, currentSort)) $scope.fetch();
});
- // update dataLP source when filters update
+ // update data source when filters update
subscriptions.add(subscribeWithScope($scope, filterManager.getUpdates$(), {
next: () => {
$scope.filters = filterManager.getFilters();
@@ -588,12 +585,12 @@ function discoverController(
}
}));
- // fetch dataLP when filters fire fetch event
+ // fetch data when filters fire fetch event
subscriptions.add(subscribeWithScope($scope, filterManager.getUpdates$(), {
next: $scope.fetch
}));
- // update dataLP source when hitting forward/back and the query changes
+ // update data source when hitting forward/back and the query changes
$scope.$listen($state, 'fetch_with_changes', function (diff) {
if (diff.indexOf('query') >= 0) $scope.fetch();
});
@@ -633,7 +630,7 @@ function discoverController(
let prev = {};
const status = {
UNINITIALIZED: 'uninitialized',
- LOADING: 'loading', // initial dataLP load
+ LOADING: 'loading', // initial data load
READY: 'ready', // results came back
NO_RESULTS: 'none' // no results came back
};
@@ -704,7 +701,7 @@ function discoverController(
savedSearchTitle: savedSearch.title,
}
}),
- 'dataLP-test-subj': 'saveSearchSuccess',
+ 'data-test-subj': 'saveSearchSuccess',
});
if (savedSearch.id !== $route.current.params.id) {
@@ -765,7 +762,7 @@ function discoverController(
} else {
toastNotifications.addError(error, {
title: i18n.translate('kbn.discover.errorLoadingData', {
- defaultMessage: 'Error loading dataLP',
+ defaultMessage: 'Error loading data',
}),
});
}
@@ -813,10 +810,10 @@ function discoverController(
function logInspectorRequest() {
inspectorAdapters.requests.reset();
const title = i18n.translate('kbn.discover.inspectorRequestDataTitle', {
- defaultMessage: 'dataLP',
+ defaultMessage: 'data',
});
const description = i18n.translate('kbn.discover.inspectorRequestDescription', {
- defaultMessage: 'This request queries Elasticsearch to fetch the dataLP for the search.',
+ defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.',
});
inspectorRequest = inspectorAdapters.requests.start(title, { description });
inspectorRequest.stats(getRequestInspectorStats($scope.searchSource));
@@ -972,7 +969,7 @@ function discoverController(
return;
}
if (!$scope.savedQuery || newSavedQueryId !== $scope.savedQuery.id) {
- savedQueryService.getSavedQuery(newSavedQueryId).then((savedQuery) => {
+ getSavedQuery(newSavedQueryId).then((savedQuery) => {
$scope.$evalAsync(() => {
$scope.savedQuery = savedQuery;
updateStateFromSavedQuery(savedQuery);
diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_header/table_header.test.tsx b/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_header/table_header.test.tsx
index 09ba77c7c4999..e5706b5e3c9bb 100644
--- a/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_header/table_header.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_header/table_header.test.tsx
@@ -23,7 +23,7 @@ import { TableHeader } from './table_header';
// @ts-ignore
import { findTestSubject } from '@elastic/eui/lib/test';
import { SortOrder } from './helpers';
-import { IndexPattern, FieldType } from '../../../../kibana_services';
+import { IndexPattern, IFieldType } from '../../../../kibana_services';
function getMockIndexPattern() {
return ({
@@ -40,7 +40,7 @@ function getMockIndexPattern() {
aggregatable: false,
searchable: true,
sortable: true,
- } as FieldType;
+ } as IFieldType;
} else {
return {
name,
@@ -48,7 +48,7 @@ function getMockIndexPattern() {
aggregatable: false,
searchable: true,
sortable: false,
- } as FieldType;
+ } as IFieldType;
}
},
} as unknown) as IndexPattern;
diff --git a/src/legacy/core_plugins/kibana/public/discover/components/doc/doc.tsx b/src/legacy/core_plugins/kibana/public/discover/components/doc/doc.tsx
index 85308d9c7e03e..7020addb2bc6d 100644
--- a/src/legacy/core_plugins/kibana/public/discover/components/doc/doc.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/components/doc/doc.tsx
@@ -19,9 +19,10 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiCallOut, EuiLink, EuiLoadingSpinner, EuiPageContent } from '@elastic/eui';
+import { IndexPatternsContract } from 'src/plugins/data/public';
import { DocViewer } from '../doc_viewer/doc_viewer';
import { ElasticRequestState, useEsDocSearch } from './use_es_doc_search';
-import { IndexPatterns, ElasticSearchHit, getServices } from '../../kibana_services';
+import { ElasticSearchHit, getServices } from '../../kibana_services';
export interface ElasticSearchResult {
hits: {
@@ -50,7 +51,7 @@ export interface DocProps {
/**
* IndexPatternService to get a given index pattern by ID
*/
- indexPatternService: IndexPatterns;
+ indexPatternService: IndexPatternsContract;
/**
* Client of ElasticSearch to use for the query
*/
diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.js b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.js
index cc3d864fd371e..8674726a81076 100644
--- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.js
+++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.js
@@ -23,7 +23,7 @@ import { fieldCalculator } from './lib/field_calculator';
import './discover_field';
import './discover_field_search_directive';
import './discover_index_pattern_directive';
-import { FieldList } from '../../kibana_services';
+import { FieldList } from '../../../../../../../plugins/data/public';
import fieldChooserTemplate from './field_chooser.html';
export function createFieldChooserDirective($location, config, $route) {
diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
index 8e2d15ae48a1f..f6982e13d7d03 100644
--- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
@@ -25,6 +25,8 @@ import 'ui/angular-bootstrap';
import { IPrivate } from 'ui/private';
import { EuiIcon } from '@elastic/eui';
// @ts-ignore
+import { StateProvider } from 'ui/state_management/state';
+// @ts-ignore
import { EventsProvider } from 'ui/events';
import { PersistedState } from 'ui/persisted_state';
// @ts-ignore
@@ -277,6 +279,9 @@ function createLocalAppStateModule() {
})
.service('getAppState', function(Private: any) {
return Private(AppStateProvider).getAppState;
+ })
+ .service('State', function(Private: any) {
+ return Private(StateProvider);
});
}
@@ -301,7 +306,7 @@ function createElasticSearchModule() {
}
function createIndexPatternsModule() {
- angular.module('discoverIndexPatterns', []).service('indexPatterns', IndexPatterns);
+ angular.module('discoverIndexPatterns', []).value('indexPatterns', IndexPatterns);
}
function createPagerFactoryModule() {
diff --git a/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts
index 51f1521504be8..b72bd27a31cf9 100644
--- a/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts
@@ -27,16 +27,12 @@ import {
import * as docViewsRegistry from 'ui/registry/doc_views';
import chromeLegacy from 'ui/chrome';
import { IPrivate } from 'ui/private';
-import { FilterManager, TimefilterContract } from 'src/plugins/data/public';
-// @ts-ignore
-import { StateProvider } from 'ui/state_management/state';
+import { FilterManager, TimefilterContract, IndexPatternsContract } from 'src/plugins/data/public';
// @ts-ignore
import { createSavedSearchesService } from '../saved_searches/saved_searches';
// @ts-ignore
import { createSavedSearchFactory } from '../saved_searches/_saved_search';
import { DiscoverStartPlugins } from '../plugin';
-import { start as legacyData } from '../../../../data/public/legacy';
-import { DataStart, IndexPatterns } from '../../../../data/public';
import { EuiUtilsStart } from '../../../../../../plugins/eui_utils/public';
import { SavedSearch } from '../types';
import { SharePluginStart } from '../../../../../../plugins/share/public';
@@ -46,12 +42,11 @@ export interface DiscoverServices {
capabilities: Capabilities;
chrome: ChromeStart;
core: CoreStart;
- data: DataStart;
docLinks: DocLinksStart;
docViewsRegistry: docViewsRegistry.DocViewsRegistry;
eui_utils: EuiUtilsStart;
filterManager: FilterManager;
- indexPatterns: IndexPatterns;
+ indexPatterns: IndexPatternsContract;
inspector: unknown;
metadata: { branch: string };
share: SharePluginStart;
@@ -60,7 +55,6 @@ export interface DiscoverServices {
// legacy
getSavedSearchById: (id: string) => Promise;
getSavedSearchUrlById: (id: string) => Promise;
- State: unknown;
uiSettings: IUiSettingsClient;
}
@@ -68,13 +62,11 @@ export async function buildGlobalAngularServices() {
const injector = await chromeLegacy.dangerouslyGetActiveInjector();
const Private = injector.get('Private');
const kbnUrl = injector.get('kbnUrl');
- const State = Private(StateProvider);
const SavedSearchFactory = createSavedSearchFactory(Private);
const service = createSavedSearchesService(Private, SavedSearchFactory, kbnUrl, chromeLegacy);
return {
getSavedSearchById: async (id: string) => service.get(id),
getSavedSearchUrlById: async (id: string) => service.urlFor(id),
- State,
};
}
@@ -98,7 +90,7 @@ export async function buildServices(core: CoreStart, plugins: DiscoverStartPlugi
docViewsRegistry,
eui_utils: plugins.eui_utils,
filterManager: plugins.data.query.filterManager,
- indexPatterns: legacyData.indexPatterns.indexPatterns,
+ indexPatterns: plugins.data.indexPatterns,
inspector: plugins.inspector,
// @ts-ignore
metadata: core.injectedMetadata.getLegacyMetadata(),
diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
index 0d9dab96d6120..d13d0dc868a58 100644
--- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
@@ -67,7 +67,6 @@ export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
// @ts-ignore
export { RequestAdapter } from 'ui/inspector/adapters';
export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
-export { FieldList } from 'ui/index_patterns';
export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
@@ -78,11 +77,16 @@ export { tabifyAggResponse } from 'ui/agg_response/tabify';
// @ts-ignore
export { vislibSeriesResponseHandlerProvider } from 'ui/vis/response_handlers/vislib';
export { ensureDefaultIndexPattern } from 'ui/legacy_compat';
-export { unhashUrl } from 'ui/state_management/state_hashing';
+export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
// EXPORT types
export { Vis } from 'ui/vis';
-export { IndexPatterns, IndexPattern, FieldType } from 'ui/index_patterns';
+export {
+ IndexPatternsContract,
+ IIndexPattern,
+ IndexPattern,
+ IFieldType,
+} from '../../../../../plugins/data/public';
export { ElasticSearchHit } from 'ui/registry/doc_views_types';
export { DocViewRenderProps, DocViewRenderFn } from 'ui/registry/doc_views';
export { Adapters } from 'ui/inspector/types';
diff --git a/src/legacy/core_plugins/kibana/public/home/index.ts b/src/legacy/core_plugins/kibana/public/home/index.ts
index 6494cc79640e1..bd3a0b38ec3f0 100644
--- a/src/legacy/core_plugins/kibana/public/home/index.ts
+++ b/src/legacy/core_plugins/kibana/public/home/index.ts
@@ -23,7 +23,6 @@ import chrome from 'ui/chrome';
import { IPrivate } from 'ui/private';
import { HomePlugin, LegacyAngularInjectedDependencies } from './plugin';
import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
-import { start as data } from '../../../data/public/legacy';
import { TelemetryOptInProvider } from '../../../telemetry/public/services';
export const trackUiMetric = createUiStatsReporter('Kibana_home');
@@ -74,6 +73,6 @@ let copiedLegacyCatalogue = false;
},
});
instance.start(npStart.core, {
- data,
+ data: npStart.plugins.data,
});
})();
diff --git a/src/legacy/core_plugins/kibana/public/home/plugin.ts b/src/legacy/core_plugins/kibana/public/home/plugin.ts
index bb0e7e3611616..fc1747d71d069 100644
--- a/src/legacy/core_plugins/kibana/public/home/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/home/plugin.ts
@@ -20,7 +20,7 @@
import { CoreSetup, CoreStart, LegacyNavLink, Plugin, UiSettingsState } from 'kibana/public';
import { UiStatsMetricType } from '@kbn/analytics';
-import { DataStart } from '../../../data/public';
+import { DataPublicPluginStart } from 'src/plugins/data/public';
import { setServices } from './kibana_services';
import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public';
import { FeatureCatalogueEntry } from '../../../../../plugins/home/public';
@@ -31,7 +31,7 @@ export interface LegacyAngularInjectedDependencies {
}
export interface HomePluginStartDependencies {
- data: DataStart;
+ data: DataPublicPluginStart;
}
export interface HomePluginSetupDependencies {
@@ -58,7 +58,7 @@ export interface HomePluginSetupDependencies {
}
export class HomePlugin implements Plugin {
- private dataStart: DataStart | null = null;
+ private dataStart: DataPublicPluginStart | null = null;
private savedObjectsClient: any = null;
setup(
@@ -85,7 +85,7 @@ export class HomePlugin implements Plugin {
uiSettings: core.uiSettings,
addBasePath: core.http.basePath.prepend,
getBasePath: core.http.basePath.get,
- indexPatternService: this.dataStart!.indexPatterns.indexPatterns,
+ indexPatternService: this.dataStart!.indexPatterns,
...angularDependencies,
});
const { renderApp } = await import('./render_app');
diff --git a/src/legacy/core_plugins/kibana/public/index.scss b/src/legacy/core_plugins/kibana/public/index.scss
index 7a6a3ca1d01d0..611fe613ad99c 100644
--- a/src/legacy/core_plugins/kibana/public/index.scss
+++ b/src/legacy/core_plugins/kibana/public/index.scss
@@ -1,8 +1,6 @@
@import 'src/legacy/ui/public/styles/styling_constants';
// Elastic charts
-@import '@elastic/eui/src/components/tool_tip/variables';
-@import '@elastic/eui/src/components/tool_tip/mixins';
@import '@elastic/charts/dist/theme';
@import '@elastic/eui/src/themes/charts/theme';
diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js
index cc438d338c7d5..0045819257018 100644
--- a/src/legacy/core_plugins/kibana/public/kibana.js
+++ b/src/legacy/core_plugins/kibana/public/kibana.js
@@ -29,7 +29,6 @@ import { npSetup } from 'ui/new_platform';
import 'uiExports/home';
import 'uiExports/visTypes';
-import 'uiExports/visEditorTypes';
import 'uiExports/visualize';
import 'uiExports/savedObjectTypes';
import 'uiExports/fieldFormatEditors';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js
index 5cb93a36cdd18..1e894664c2bf1 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js
@@ -50,8 +50,6 @@ export class StepTimeField extends Component {
constructor(props) {
super(props);
- const { getIndexPatternType, getIndexPatternName } = props.indexPatternCreationType;
-
this.state = {
error: '',
timeFields: [],
@@ -61,8 +59,8 @@ export class StepTimeField extends Component {
isFetchingTimeFields: false,
isCreating: false,
indexPatternId: '',
- indexPatternType: getIndexPatternType(),
- indexPatternName: getIndexPatternName(),
+ indexPatternType: props.indexPatternCreationType.getIndexPatternType(),
+ indexPatternName: props.indexPatternCreationType.getIndexPatternName(),
};
}
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js
index b500f5c79e98b..833ca8467292e 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js
@@ -21,7 +21,7 @@ import { SavedObjectsClientProvider } from 'ui/saved_objects';
import uiRoutes from 'ui/routes';
import angularTemplate from './angular_template.html';
import 'ui/index_patterns';
-import { IndexPatternCreationFactory } from 'ui/management/index_pattern_creation';
+import { setup as managementSetup } from '../../../../../../management/public/legacy';
import { getCreateBreadcrumbs } from '../breadcrumbs';
import { renderCreateIndexPatternWizard, destroyCreateIndexPatternWizard } from './render';
@@ -35,8 +35,9 @@ uiRoutes.when('/management/kibana/index_pattern', {
const Private = $injector.get('Private');
$scope.$$postDigest(() => {
const $routeParams = $injector.get('$routeParams');
- const indexPatternCreationProvider = Private(IndexPatternCreationFactory)($routeParams.type);
- const indexPatternCreationType = indexPatternCreationProvider.getType();
+ const indexPatternCreationType = managementSetup.indexPattern.creation.getType(
+ $routeParams.type
+ );
const services = {
config: $injector.get('config'),
es: $injector.get('es'),
@@ -52,12 +53,9 @@ uiRoutes.when('/management/kibana/index_pattern', {
const initialQuery = $routeParams.id ? decodeURIComponent($routeParams.id) : undefined;
- renderCreateIndexPatternWizard(
- initialQuery,
- services
- );
+ renderCreateIndexPatternWizard(initialQuery, services);
});
$scope.$on('$destroy', destroyCreateIndexPatternWizard);
- }
+ },
});
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js
index 6ae84b9c641c2..150fae6e87dde 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js
@@ -28,7 +28,7 @@ import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import template from './edit_index_pattern.html';
import { fieldWildcardMatcher } from 'ui/field_wildcard';
-import { IndexPatternListFactory } from 'ui/management/index_pattern_list';
+import { setup as managementSetup } from '../../../../../../management/public/legacy';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { SourceFiltersTable } from './source_filters_table';
@@ -58,13 +58,17 @@ function updateSourceFiltersTable($scope, $state) {
filterFilter={$scope.fieldFilter}
fieldWildcardMatcher={$scope.fieldWildcardMatcher}
onAddOrRemoveFilter={() => {
- $scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, $scope.indexPatternListProvider);
+ $scope.editSections = $scope.editSectionsProvider(
+ $scope.indexPattern,
+ $scope.fieldFilter,
+ $scope.indexPatternListProvider
+ );
$scope.refreshFilters();
$scope.$apply();
}}
/>
,
- node,
+ node
);
});
} else {
@@ -77,7 +81,6 @@ function destroySourceFiltersTable() {
node && unmountComponentAtNode(node);
}
-
function updateScriptedFieldsTable($scope, $state) {
if ($state.tab === 'scriptedFields') {
$scope.$$postDigest(() => {
@@ -100,13 +103,17 @@ function updateScriptedFieldsTable($scope, $state) {
getRouteHref: (obj, route) => $scope.kbnUrl.getRouteHref(obj, route),
}}
onRemoveField={() => {
- $scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, $scope.indexPatternListProvider);
+ $scope.editSections = $scope.editSectionsProvider(
+ $scope.indexPattern,
+ $scope.fieldFilter,
+ $scope.indexPatternListProvider
+ );
$scope.refreshFilters();
$scope.$apply();
}}
/>
,
- node,
+ node
);
});
} else {
@@ -144,7 +151,7 @@ function updateIndexedFieldsTable($scope, $state) {
}}
/>
,
- node,
+ node
);
});
} else {
@@ -157,34 +164,36 @@ function destroyIndexedFieldsTable() {
node && unmountComponentAtNode(node);
}
-uiRoutes
- .when('/management/kibana/index_patterns/:indexPatternId', {
- template,
- k7Breadcrumbs: getEditBreadcrumbs,
- resolve: {
- indexPattern: function ($route, Promise, redirectWhenMissing, indexPatterns) {
- return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId))
- .catch(redirectWhenMissing('/management/kibana/index_patterns'));
- }
+uiRoutes.when('/management/kibana/index_patterns/:indexPatternId', {
+ template,
+ k7Breadcrumbs: getEditBreadcrumbs,
+ resolve: {
+ indexPattern: function ($route, Promise, redirectWhenMissing, indexPatterns) {
+ return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId)).catch(
+ redirectWhenMissing('/management/kibana/index_patterns')
+ );
},
- });
+ },
+});
-uiModules.get('apps/management')
+uiModules
+ .get('apps/management')
.controller('managementIndexPatternsEdit', function (
$scope, $location, $route, Promise, config, indexPatterns, Private, AppState, confirmModal) {
const $state = $scope.state = new AppState();
- const indexPatternListProvider = Private(IndexPatternListFactory)();
$scope.fieldWildcardMatcher = (...args) => fieldWildcardMatcher(...args, config.get('metaFields'));
$scope.editSectionsProvider = Private(IndicesEditSectionsProvider);
$scope.kbnUrl = Private(KbnUrlProvider);
$scope.indexPattern = $route.current.locals.indexPattern;
- $scope.indexPatternListProvider = indexPatternListProvider;
- $scope.indexPattern.tags = indexPatternListProvider.getIndexPatternTags(
+ $scope.indexPatternListProvider = managementSetup.indexPattern.list;
+ $scope.indexPattern.tags = managementSetup.indexPattern.list.getIndexPatternTags(
$scope.indexPattern,
$scope.indexPattern.id === config.get('defaultIndex')
);
- $scope.getFieldInfo = indexPatternListProvider.getFieldInfo;
+ $scope.getFieldInfo = managementSetup.indexPattern.list.getFieldInfo.bind(
+ managementSetup.indexPattern.list
+ );
docTitle.change($scope.indexPattern.title);
const otherPatterns = _.filter($route.current.locals.indexPatterns, pattern => {
@@ -192,7 +201,11 @@ uiModules.get('apps/management')
});
$scope.$watch('indexPattern.fields', function () {
- $scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, indexPatternListProvider);
+ $scope.editSections = $scope.editSectionsProvider(
+ $scope.indexPattern,
+ $scope.fieldFilter,
+ managementSetup.indexPattern.list
+ );
$scope.refreshFilters();
$scope.fields = $scope.indexPattern.getNonScriptedFields();
updateIndexedFieldsTable($scope, $state);
@@ -231,26 +244,26 @@ uiModules.get('apps/management')
});
$scope.$watchCollection('indexPattern.fields', function () {
- $scope.conflictFields = $scope.indexPattern.fields
- .filter(field => field.type === 'conflict');
+ $scope.conflictFields = $scope.indexPattern.fields.filter(field => field.type === 'conflict');
});
$scope.refreshFields = function () {
const confirmMessage = i18n.translate('kbn.management.editIndexPattern.refreshLabel', {
- defaultMessage: 'This action resets the popularity counter of each field.'
+ defaultMessage: 'This action resets the popularity counter of each field.',
});
const confirmModalOptions = {
- confirmButtonText: i18n.translate('kbn.management.editIndexPattern.refreshButton', { defaultMessage: 'Refresh' }),
+ confirmButtonText: i18n.translate('kbn.management.editIndexPattern.refreshButton', {
+ defaultMessage: 'Refresh',
+ }),
onConfirm: async () => {
await $scope.indexPattern.init(true);
$scope.fields = $scope.indexPattern.getNonScriptedFields();
},
- title: i18n.translate('kbn.management.editIndexPattern.refreshHeader', { defaultMessage: 'Refresh field list?' })
+ title: i18n.translate('kbn.management.editIndexPattern.refreshHeader', {
+ defaultMessage: 'Refresh field list?',
+ }),
};
- confirmModal(
- confirmMessage,
- confirmModalOptions
- );
+ confirmModal(confirmMessage, confirmModalOptions);
};
$scope.removePattern = function () {
@@ -271,9 +284,13 @@ uiModules.get('apps/management')
}
const confirmModalOptions = {
- confirmButtonText: i18n.translate('kbn.management.editIndexPattern.deleteButton', { defaultMessage: 'Delete' }),
+ confirmButtonText: i18n.translate('kbn.management.editIndexPattern.deleteButton', {
+ defaultMessage: 'Delete',
+ }),
onConfirm: doRemove,
- title: i18n.translate('kbn.management.editIndexPattern.deleteHeader', { defaultMessage: 'Delete index pattern?' })
+ title: i18n.translate('kbn.management.editIndexPattern.deleteHeader', {
+ defaultMessage: 'Delete index pattern?',
+ }),
};
confirmModal('', confirmModalOptions);
};
@@ -285,7 +302,8 @@ uiModules.get('apps/management')
$scope.setIndexPatternsTimeField = function (field) {
if (field.type !== 'date') {
const errorMessage = i18n.translate('kbn.management.editIndexPattern.notDateErrorMessage', {
- defaultMessage: 'That field is a {fieldType} not a date.', values: { fieldType: field.type }
+ defaultMessage: 'That field is a {fieldType} not a date.',
+ values: { fieldType: field.type },
});
toastNotifications.addDanger(errorMessage);
return;
@@ -295,12 +313,16 @@ uiModules.get('apps/management')
};
$scope.$watch('fieldFilter', () => {
- $scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, indexPatternListProvider);
+ $scope.editSections = $scope.editSectionsProvider(
+ $scope.indexPattern,
+ $scope.fieldFilter,
+ managementSetup.indexPattern.list
+ );
if ($scope.fieldFilter === undefined) {
return;
}
- switch($state.tab) {
+ switch ($state.tab) {
case 'indexedFields':
updateIndexedFieldsTable($scope, $state);
case 'scriptedFields':
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js
index 272544fa036cc..5935afec1dd70 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js
@@ -18,8 +18,7 @@
*/
import { management } from 'ui/management';
-import { IndexPatternListFactory } from 'ui/management/index_pattern_list';
-import { IndexPatternCreationFactory } from 'ui/management/index_pattern_creation';
+import { setup as managementSetup } from '../../../../../management/public/legacy';
import './create_index_pattern_wizard';
import './edit_index_pattern';
import uiRoutes from 'ui/routes';
@@ -28,7 +27,10 @@ import indexTemplate from './index.html';
import indexPatternListTemplate from './list.html';
import { IndexPatternTable } from './index_pattern_table';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
-import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
+import {
+ FeatureCatalogueRegistryProvider,
+ FeatureCatalogueCategory,
+} from 'ui/registry/feature_catalogue';
import { i18n } from '@kbn/i18n';
import { I18nContext } from 'ui/i18n';
import { UICapabilitiesProvider } from 'ui/capabilities/react';
@@ -39,11 +41,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
const INDEX_PATTERN_LIST_DOM_ELEMENT_ID = 'indexPatternListReact';
-export function updateIndexPatternList(
- indexPatterns,
- kbnUrl,
- indexPatternCreationOptions,
-) {
+export function updateIndexPatternList(indexPatterns, kbnUrl, indexPatternCreationOptions) {
const node = document.getElementById(INDEX_PATTERN_LIST_DOM_ELEMENT_ID);
if (!node) {
return;
@@ -59,7 +57,7 @@ export function updateIndexPatternList(
/>
,
- node,
+ node
);
}
@@ -72,55 +70,56 @@ const indexPatternsResolutions = {
indexPatterns: function (Private) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
- return savedObjectsClient.find({
- type: 'index-pattern',
- fields: ['title', 'type'],
- perPage: 10000
- }).then(response => response.savedObjects);
- }
+ return savedObjectsClient
+ .find({
+ type: 'index-pattern',
+ fields: ['title', 'type'],
+ perPage: 10000,
+ })
+ .then(response => response.savedObjects);
+ },
};
// add a dependency to all of the subsection routes
-uiRoutes
- .defaults(/management\/kibana\/(index_patterns|index_pattern)/, {
- resolve: indexPatternsResolutions,
- requireUICapability: 'management.kibana.index_patterns',
- badge: uiCapabilities => {
- if (uiCapabilities.indexPatterns.save) {
- return undefined;
- }
-
- return {
- text: i18n.translate('kbn.management.indexPatterns.badge.readOnly.text', {
- defaultMessage: 'Read only',
- }),
- tooltip: i18n.translate('kbn.management.indexPatterns.badge.readOnly.tooltip', {
- defaultMessage: 'Unable to save index patterns',
- }),
- iconType: 'glasses'
- };
+uiRoutes.defaults(/management\/kibana\/(index_patterns|index_pattern)/, {
+ resolve: indexPatternsResolutions,
+ requireUICapability: 'management.kibana.index_patterns',
+ badge: uiCapabilities => {
+ if (uiCapabilities.indexPatterns.save) {
+ return undefined;
}
- });
-uiRoutes
- .when('/management/kibana/index_patterns', {
- template: indexPatternListTemplate,
- k7Breadcrumbs: getListBreadcrumbs
- });
+ return {
+ text: i18n.translate('kbn.management.indexPatterns.badge.readOnly.text', {
+ defaultMessage: 'Read only',
+ }),
+ tooltip: i18n.translate('kbn.management.indexPatterns.badge.readOnly.tooltip', {
+ defaultMessage: 'Unable to save index patterns',
+ }),
+ iconType: 'glasses',
+ };
+ },
+});
+
+uiRoutes.when('/management/kibana/index_patterns', {
+ template: indexPatternListTemplate,
+ k7Breadcrumbs: getListBreadcrumbs,
+});
// wrapper directive, which sets some global stuff up like the left nav
-uiModules.get('apps/management')
- .directive('kbnManagementIndexPatterns', function ($route, config, kbnUrl, Private) {
+uiModules
+ .get('apps/management')
+ .directive('kbnManagementIndexPatterns', function ($route, config, kbnUrl) {
return {
restrict: 'E',
transclude: true,
template: indexTemplate,
link: async function ($scope) {
- const indexPatternListProvider = Private(IndexPatternListFactory)();
- const indexPatternCreationProvider = Private(IndexPatternCreationFactory)();
- const indexPatternCreationOptions = await indexPatternCreationProvider.getIndexPatternCreationOptions((url) => {
- $scope.$evalAsync(() => kbnUrl.change(url));
- });
+ const indexPatternCreationOptions = await managementSetup.indexPattern.creation.getIndexPatternCreationOptions(
+ url => {
+ $scope.$evalAsync(() => kbnUrl.change(url));
+ }
+ );
const renderList = () => {
$scope.indexPatternList =
@@ -129,7 +128,7 @@ uiModules.get('apps/management')
const id = pattern.id;
const title = pattern.get('title');
const isDefault = $scope.defaultIndex === id;
- const tags = indexPatternListProvider.getIndexPatternTags(
+ const tags = managementSetup.indexPattern.list.getIndexPatternTags(
pattern,
isDefault
);
@@ -165,25 +164,30 @@ uiModules.get('apps/management')
$scope.$watch('defaultIndex', () => renderList());
config.bindToScope($scope, 'defaultIndex');
$scope.$apply();
- }
+ },
};
});
management.getSection('kibana').register('index_patterns', {
- display: i18n.translate('kbn.management.indexPattern.sectionsHeader', { defaultMessage: 'Index Patterns' }),
+ display: i18n.translate('kbn.management.indexPattern.sectionsHeader', {
+ defaultMessage: 'Index Patterns',
+ }),
order: 0,
- url: '#/management/kibana/index_patterns/'
+ url: '#/management/kibana/index_patterns/',
});
FeatureCatalogueRegistryProvider.register(() => {
return {
id: 'index_patterns',
- title: i18n.translate('kbn.management.indexPatternHeader', { defaultMessage: 'Index Patterns' }),
- description: i18n.translate('kbn.management.indexPatternLabel',
- { defaultMessage: 'Manage the index patterns that help retrieve your data from Elasticsearch.' }),
+ title: i18n.translate('kbn.management.indexPatternHeader', {
+ defaultMessage: 'Index Patterns',
+ }),
+ description: i18n.translate('kbn.management.indexPatternLabel', {
+ defaultMessage: 'Manage the index patterns that help retrieve your data from Elasticsearch.',
+ }),
icon: 'indexPatternApp',
path: '/app/kibana#/management/kibana/index_patterns',
showOnHomePage: true,
- category: FeatureCatalogueCategory.ADMIN
+ category: FeatureCatalogueCategory.ADMIN,
};
});
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
index 5956b6c306b0e..1c3666ac0980c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
@@ -19,6 +19,7 @@
import React from 'react';
import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
+import { mockManagementPlugin } from '../../../../../../../../management/public/np_ready/mocks';
import { Query } from '@elastic/eui';
import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table';
@@ -29,6 +30,11 @@ import { extractExportDetails } from '../../../lib/extract_export_details';
jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
+jest.mock('../../../../../../../../management/public/legacy', () => ({
+ setup: mockManagementPlugin.createSetupContract(),
+ start: mockManagementPlugin.createStartContract(),
+}));
+
jest.mock('../../../lib/find_objects', () => ({
findObjects: jest.fn(),
}));
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
index e465149b301dc..97c0d5b89d657 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
@@ -19,7 +19,7 @@
import React from 'react';
import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
-
+import { mockManagementPlugin } from '../../../../../../../../../../management/public/np_ready/mocks';
import { Flyout } from '../flyout';
jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
@@ -48,6 +48,11 @@ jest.mock('../../../../../lib/resolve_saved_objects', () => ({
saveObjects: jest.fn(),
}));
+jest.mock('../../../../../../../../../../management/public/legacy', () => ({
+ setup: mockManagementPlugin.createSetupContract(),
+ start: mockManagementPlugin.createStartContract(),
+}));
+
jest.mock('ui/notify', () => ({}));
const defaultProps = {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js
index d3f5fb1945254..fba249670ce60 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js
@@ -21,6 +21,7 @@ import React from 'react';
import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { keyCodes } from '@elastic/eui/lib/services';
+import { mockManagementPlugin } from '../../../../../../../../../../management/public/np_ready/mocks';
jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
@@ -28,6 +29,11 @@ jest.mock('ui/chrome', () => ({
addBasePath: () => '',
}));
+jest.mock('../../../../../../../../../../management/public/legacy', () => ({
+ setup: mockManagementPlugin.createSetupContract(),
+ start: mockManagementPlugin.createStartContract(),
+}));
+
import { Table } from '../table';
const defaultProps = {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
index 43cf8c2a23286..eeddc390037a6 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
@@ -18,7 +18,7 @@
*/
import chrome from 'ui/chrome';
-import { SavedObjectsManagementActionRegistry } from 'ui/management/saved_objects_management';
+import { setup as managementSetup } from '../../../../../../../../../management/public/legacy';
import React, { PureComponent, Fragment } from 'react';
import PropTypes from 'prop-types';
@@ -79,7 +79,7 @@ export class Table extends PureComponent {
constructor(props) {
super(props);
- this.extraActions = SavedObjectsManagementActionRegistry.get();
+ this.extraActions = managementSetup.savedObjects.registry.get();
}
onChange = ({ query, error }) => {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js
index 162fae33ba19e..22c3e372230f5 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js
@@ -17,7 +17,6 @@
* under the License.
*/
-import { SavedObjectNotFound } from '../../../../../../../../plugins/kibana_utils/public';
import { i18n } from '@kbn/i18n';
async function getSavedObject(doc, services) {
@@ -255,7 +254,8 @@ export async function resolveSavedObjects(savedObjects, overwriteAll, services,
importedObjectCount++;
}
} catch (error) {
- if (error instanceof SavedObjectNotFound) {
+
+ if (error.constructor.name === 'SavedObjectNotFound') {
if (error.savedObjectType === 'index-pattern') {
conflictedIndexPatterns.push({ obj, doc: searchDoc });
} else {
@@ -275,7 +275,7 @@ export async function resolveSavedObjects(savedObjects, overwriteAll, services,
importedObjectCount++;
}
} catch (error) {
- const isIndexPatternNotFound = error instanceof SavedObjectNotFound &&
+ const isIndexPatternNotFound = error.constructor.name === 'SavedObjectNotFound' &&
error.savedObjectType === 'index-pattern';
if (isIndexPatternNotFound && obj.savedSearchId) {
conflictedSavedObjectsLinkedToSavedSearches.push(obj);
diff --git a/src/legacy/core_plugins/kibana/public/visualize/application.ts b/src/legacy/core_plugins/kibana/public/visualize/application.ts
new file mode 100644
index 0000000000000..7684f982de7e0
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/application.ts
@@ -0,0 +1,193 @@
+/*
+ * 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 angular, { IModule } from 'angular';
+import { EuiConfirmModal } from '@elastic/eui';
+import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
+
+import { AppMountContext, LegacyCoreStart } from 'kibana/public';
+import {
+ AppStateProvider,
+ AppState,
+ configureAppAngularModule,
+ confirmModalFactory,
+ createTopNavDirective,
+ createTopNavHelper,
+ EventsProvider,
+ GlobalStateProvider,
+ KbnUrlProvider,
+ RedirectWhenMissingProvider,
+ IPrivate,
+ PersistedState,
+ PrivateProvider,
+ PromiseServiceCreator,
+ StateManagementConfigProvider,
+} from './legacy_imports';
+import { NavigationStart } from '../../../navigation/public';
+
+// @ts-ignore
+import { initVisualizeApp } from './legacy_app';
+import { VisualizeKibanaServices } from './kibana_services';
+
+let angularModuleInstance: IModule | null = null;
+
+export const renderApp = async (
+ element: HTMLElement,
+ appBasePath: string,
+ deps: VisualizeKibanaServices
+) => {
+ if (!angularModuleInstance) {
+ angularModuleInstance = createLocalAngularModule(deps.core, deps.navigation);
+ // global routing stuff
+ configureAppAngularModule(angularModuleInstance, deps.core as LegacyCoreStart, true);
+ // custom routing stuff
+ initVisualizeApp(angularModuleInstance, deps);
+ }
+ const $injector = mountVisualizeApp(appBasePath, element);
+ return () => $injector.get('$rootScope').$destroy();
+};
+
+const mainTemplate = (basePath: string) => `
+`;
+
+const moduleName = 'app/visualize';
+
+const thirdPartyAngularDependencies = ['ngSanitize', 'ngRoute', 'react'];
+
+function mountVisualizeApp(appBasePath: string, element: HTMLElement) {
+ const mountpoint = document.createElement('div');
+ mountpoint.setAttribute('style', 'height: 100%');
+ mountpoint.innerHTML = mainTemplate(appBasePath);
+ // bootstrap angular into detached element and attach it later to
+ // make angular-within-angular possible
+ const $injector = angular.bootstrap(mountpoint, [moduleName]);
+ // initialize global state handler
+ element.appendChild(mountpoint);
+ return $injector;
+}
+
+function createLocalAngularModule(core: AppMountContext['core'], navigation: NavigationStart) {
+ createLocalI18nModule();
+ createLocalPrivateModule();
+ createLocalPromiseModule();
+ createLocalConfigModule(core);
+ createLocalKbnUrlModule();
+ createLocalStateModule();
+ createLocalPersistedStateModule();
+ createLocalTopNavModule(navigation);
+ createLocalConfirmModalModule();
+
+ const visualizeAngularModule: IModule = angular.module(moduleName, [
+ ...thirdPartyAngularDependencies,
+ 'app/visualize/Config',
+ 'app/visualize/I18n',
+ 'app/visualize/Private',
+ 'app/visualize/PersistedState',
+ 'app/visualize/TopNav',
+ 'app/visualize/State',
+ 'app/visualize/ConfirmModal',
+ ]);
+ return visualizeAngularModule;
+}
+
+function createLocalConfirmModalModule() {
+ angular
+ .module('app/visualize/ConfirmModal', ['react'])
+ .factory('confirmModal', confirmModalFactory)
+ .directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal));
+}
+
+function createLocalStateModule() {
+ angular
+ .module('app/visualize/State', [
+ 'app/visualize/Private',
+ 'app/visualize/Config',
+ 'app/visualize/KbnUrl',
+ 'app/visualize/Promise',
+ 'app/visualize/PersistedState',
+ ])
+ .factory('AppState', function(Private: IPrivate) {
+ return Private(AppStateProvider);
+ })
+ .service('getAppState', function(Private: IPrivate) {
+ return Private(AppStateProvider).getAppState;
+ })
+ .service('globalState', function(Private: IPrivate) {
+ return Private(GlobalStateProvider);
+ });
+}
+
+function createLocalPersistedStateModule() {
+ angular
+ .module('app/visualize/PersistedState', ['app/visualize/Private', 'app/visualize/Promise'])
+ .factory('PersistedState', (Private: IPrivate) => {
+ const Events = Private(EventsProvider);
+ return class AngularPersistedState extends PersistedState {
+ constructor(value: any, path: any) {
+ super(value, path, Events);
+ }
+ };
+ });
+}
+
+function createLocalKbnUrlModule() {
+ angular
+ .module('app/visualize/KbnUrl', ['app/visualize/Private', 'ngRoute'])
+ .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
+ .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
+}
+
+function createLocalConfigModule(core: AppMountContext['core']) {
+ angular
+ .module('app/visualize/Config', ['app/visualize/Private'])
+ .provider('stateManagementConfig', StateManagementConfigProvider)
+ .provider('config', () => {
+ return {
+ $get: () => ({
+ get: core.uiSettings.get.bind(core.uiSettings),
+ }),
+ };
+ });
+}
+
+function createLocalPromiseModule() {
+ angular.module('app/visualize/Promise', []).service('Promise', PromiseServiceCreator);
+}
+
+function createLocalPrivateModule() {
+ angular.module('app/visualize/Private', []).provider('Private', PrivateProvider);
+}
+
+function createLocalTopNavModule(navigation: NavigationStart) {
+ angular
+ .module('app/visualize/TopNav', ['react'])
+ .directive('kbnTopNav', createTopNavDirective)
+ .directive('kbnTopNavHelper', createTopNavHelper(navigation.ui));
+}
+
+function createLocalI18nModule() {
+ angular
+ .module('app/visualize/I18n', [])
+ .provider('i18n', I18nProvider)
+ .filter('i18n', i18nFilter)
+ .directive('i18nId', i18nDirective);
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.html b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.html
index bf9ac9b9bbe36..6190b92c9be3e 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.html
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.html
@@ -39,7 +39,7 @@
show-search-bar="true"
show-query-bar="true"
show-query-input="showQueryInput()"
- show-filter-bar="showFilterBar() && chrome.getVisible()"
+ show-filter-bar="showFilterBar() && isVisible"
show-date-picker="showQueryBarTimePicker()"
show-auto-refresh-only="!showQueryBarTimePicker()"
query="state.query"
@@ -67,7 +67,7 @@
-->
savedVisualizations.get($route.current.params))
- .then(savedVis => {
- if (savedVis.vis.type.setup) {
- return savedVis.vis.type.setup(savedVis)
- .catch(() => savedVis);
- }
- return savedVis;
- })
- .catch(redirectWhenMissing({
- '*': '/visualize'
- }));
- }
- }
- })
- .when(`${VisualizeConstants.EDIT_PATH}/:id`, {
- template: editorTemplate,
- k7Breadcrumbs: getEditBreadcrumbs,
- resolve: {
- savedVis: function (savedVisualizations, redirectWhenMissing, $route, $rootScope, kbnUrl) {
- return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl)
- .then(() => savedVisualizations.get($route.current.params.id))
- .then((savedVis) => {
- chrome.recentlyAccessed.add(
- savedVis.getFullPath(),
- savedVis.title,
- savedVis.id
- );
- return savedVis;
- })
- .then(savedVis => {
- if (savedVis.vis.type.setup) {
- return savedVis.vis.type.setup(savedVis).catch(() => savedVis);
- }
- return savedVis;
- })
- .catch(
- redirectWhenMissing({
- visualization: '/visualize',
- search: '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- 'index-pattern':
- '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- 'index-pattern-field':
- '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- })
- );
- }
- }
- });
+import { getServices } from '../kibana_services';
-uiModules
- .get('app/visualize', [
- 'kibana/url'
- ])
- .directive('visualizeApp', function () {
+export function initEditorDirective(app, deps) {
+ app.directive('visualizeApp', function () {
return {
restrict: 'E',
controllerAs: 'visualizeApp',
- controller: VisEditor,
+ controller: VisualizeAppController,
};
});
-function VisEditor(
+ initVisEditorDirective(app, deps);
+ initVisualizationDirective(app, deps);
+}
+
+function VisualizeAppController(
$scope,
$element,
$route,
@@ -155,19 +70,42 @@ function VisEditor(
$window,
$injector,
$timeout,
- indexPatterns,
kbnUrl,
redirectWhenMissing,
- Private,
Promise,
- config,
kbnBaseUrl,
- localStorage,
+ getAppState,
+ globalState,
) {
- const queryFilter = Private(FilterBarQueryFilterProvider);
-
+ const {
+ indexPatterns,
+ localStorage,
+ visualizeCapabilities,
+ share,
+ data: {
+ query: {
+ filterManager,
+ timefilter: { timefilter },
+ },
+ },
+ toastNotifications,
+ legacyChrome,
+ chrome,
+ getBasePath,
+ core: { docLinks },
+ savedQueryService,
+ uiSettings,
+ } = getServices();
+
+ const filterStateManager = new FilterStateManager(globalState, getAppState, filterManager);
+ const queryFilter = filterManager;
// Retrieve the resolved SavedVis instance.
const savedVis = $route.current.locals.savedVis;
+ const _applyVis = () => {
+ $scope.$apply();
+ };
+ // This will trigger a digest cycle. This is needed when vis is updated from a global angular like in visualize_embeddable.js.
+ savedVis.vis.on('apply', _applyVis);
// vis is instance of src/legacy/ui/public/vis/vis.js.
// SearchSource is a promise-based stream of search results that can inherit from other search sources.
const { vis, searchSource } = savedVis;
@@ -178,7 +116,7 @@ function VisEditor(
dirty: !savedVis.id
};
- $scope.topNavMenu = [...(capabilities.visualize.save ? [{
+ $scope.topNavMenu = [...(visualizeCapabilities.save ? [{
id: 'save',
label: i18n.translate('kbn.topNavMenu.saveVisualizationButtonLabel', { defaultMessage: 'save' }),
description: i18n.translate('kbn.visualize.topNavMenu.saveVisualizationButtonAriaLabel', {
@@ -247,7 +185,7 @@ function VisEditor(
share.toggleShareContextMenu({
anchorElement,
allowEmbed: true,
- allowShortUrl: capabilities.visualize.createShortUrl,
+ allowShortUrl: visualizeCapabilities.createShortUrl,
shareableUrl: unhashUrl(window.location.href),
objectId: savedVis.id,
objectType: 'visualization',
@@ -296,7 +234,7 @@ function VisEditor(
let stateMonitor;
if (savedVis.id) {
- docTitle.change(savedVis.title);
+ chrome.docTitle.change(savedVis.title);
}
// Extract visualization state with filtered aggs. You can see these filtered aggs in the URL.
@@ -307,7 +245,7 @@ function VisEditor(
linked: !!savedVis.savedSearchId,
query: searchSource.getOwnField('query') || {
query: '',
- language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
+ language: localStorage.get('kibana.userQueryLanguage') || uiSettings.get('search:queryLanguage')
},
filters: searchSource.getOwnField('filter') || [],
vis: savedVisState
@@ -346,9 +284,9 @@ function VisEditor(
queryFilter.setFilters(filters);
};
- $scope.showSaveQuery = capabilities.visualize.saveQuery;
+ $scope.showSaveQuery = visualizeCapabilities.saveQuery;
- $scope.$watch(() => capabilities.visualize.saveQuery, (newCapability) => {
+ $scope.$watch(() => visualizeCapabilities.saveQuery, (newCapability) => {
$scope.showSaveQuery = newCapability;
});
@@ -456,13 +394,15 @@ function VisEditor(
}
}));
- $scope.$on('$destroy', function () {
+ $scope.$on('$destroy', () => {
if ($scope._handler) {
$scope._handler.destroy();
}
savedVis.destroy();
stateMonitor.destroy();
+ filterStateManager.destroy();
subscriptions.unsubscribe();
+ $scope.vis.off('apply', _applyVis);
});
@@ -504,7 +444,7 @@ function VisEditor(
delete $state.savedQuery;
$state.query = {
query: '',
- language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
+ language: localStorage.get('kibana.userQueryLanguage') || uiSettings.get('search:queryLanguage')
};
queryFilter.removeAll();
$state.save();
@@ -590,14 +530,14 @@ function VisEditor(
// Since we aren't reloading the page, only inserting a new browser history item, we need to manually update
// the last url for this app, so directly clicking on the Visualize tab will also bring the user to the saved
// url, not the unsaved one.
- chromeLegacy.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
+ legacyChrome.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
const lastDashboardAbsoluteUrl = chrome.navLinks.get('kibana:dashboard').url;
const dashboardParsedUrl = absoluteToParsedUrl(lastDashboardAbsoluteUrl, getBasePath());
dashboardParsedUrl.addQueryParameter(DashboardConstants.NEW_VISUALIZATION_ID_PARAM, savedVis.id);
kbnUrl.change(dashboardParsedUrl.appPath);
} else if (savedVis.id === $route.current.params.id) {
- docTitle.change(savedVis.lastSavedTitle);
+ chrome.docTitle.change(savedVis.lastSavedTitle);
chrome.setBreadcrumbs($injector.invoke(getEditBreadcrumbs));
savedVis.vis.title = savedVis.title;
savedVis.vis.description = savedVis.description;
@@ -662,7 +602,7 @@ function VisEditor(
vis.type.feedbackMessage;
};
- addHelpMenuToAppChrome(chrome);
+ addHelpMenuToAppChrome(chrome, docLinks);
init();
}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization.js b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization.js
index 198fbe19a0b7a..d3651735c1a1d 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization.js
@@ -17,13 +17,8 @@
* under the License.
*/
-import { getServices } from '../kibana_services';
-
-const { embeddables, uiModules } = getServices();
-
-uiModules
- .get('kibana/directive', ['ngSanitize'])
- .directive('visualizationEmbedded', function (Private, $timeout, getAppState) {
+export function initVisualizationDirective(app, deps) {
+ app.directive('visualizationEmbedded', function ($timeout, getAppState) {
return {
restrict: 'E',
@@ -37,7 +32,7 @@ uiModules
link: function ($scope, element) {
$scope.renderFunction = async () => {
if (!$scope._handler) {
- $scope._handler = await embeddables.getEmbeddableFactory('visualization').createFromObject($scope.savedObj, {
+ $scope._handler = await deps.embeddables.getEmbeddableFactory('visualization').createFromObject($scope.savedObj, {
timeRange: $scope.timeRange,
filters: $scope.filters || [],
query: $scope.query,
@@ -66,3 +61,4 @@ uiModules
}
};
});
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
index ead77e6bc41d5..bc6d4d4c48466 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
@@ -17,15 +17,8 @@
* under the License.
*/
-import { getServices, VisEditorTypesRegistryProvider } from '../kibana_services';
-
-const { uiModules } = getServices();
-
-uiModules
- .get('kibana/directive', ['ngSanitize'])
- .directive('visualizationEditor', function (Private, $timeout, getAppState) {
- const editorTypes = Private(VisEditorTypesRegistryProvider);
-
+export function initVisEditorDirective(app, deps) {
+ app.directive('visualizationEditor', function ($timeout, getAppState) {
return {
restrict: 'E',
scope: {
@@ -38,7 +31,8 @@ uiModules
link: function ($scope, element) {
const editorType = $scope.savedObj.vis.type.editor;
const Editor = typeof editorType === 'function' ? editorType :
- editorTypes.find(editor => editor.key === editorType);
+ deps.editorTypes.find(editor => editor.key === editorType);
+
const editor = new Editor(element[0], $scope.savedObj);
$scope.renderFunction = () => {
@@ -62,3 +56,4 @@ uiModules
}
};
});
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx
index 065feae045597..d8792a761b186 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx
@@ -19,8 +19,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
+import { Embeddable, EmbeddableOutput } from '../../../../../../plugins/embeddable/public';
-import { Embeddable, EmbeddableOutput } from '../kibana_services';
import { DisabledLabVisualization } from './disabled_lab_visualization';
import { VisualizeInput } from './visualize_embeddable';
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
index 9bc9ab99c4aff..7fe3678bb1f77 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
@@ -17,11 +17,10 @@
* under the License.
*/
-import { getServices, getFromSavedObject, VisSavedObject } from '../kibana_services';
+import { npStart } from 'ui/new_platform';
-import { IIndexPattern } from '../../../../../../plugins/data/public';
-
-const { savedObjectsClient, uiSettings } = getServices();
+import { VisSavedObject } from './visualize_embeddable';
+import { indexPatterns, IIndexPattern } from '../../../../../../plugins/data/public';
export async function getIndexPattern(
savedVis: VisSavedObject
@@ -30,7 +29,8 @@ export async function getIndexPattern(
return savedVis.vis.indexPattern;
}
- const defaultIndex = uiSettings.get('defaultIndex');
+ const savedObjectsClient = npStart.core.savedObjects.client;
+ const defaultIndex = npStart.core.uiSettings.get('defaultIndex');
if (savedVis.vis.params.index_pattern) {
const indexPatternObjects = await savedObjectsClient.find({
@@ -39,10 +39,10 @@ export async function getIndexPattern(
search: `"${savedVis.vis.params.index_pattern}"`,
searchFields: ['title'],
});
- const [indexPattern] = indexPatternObjects.savedObjects.map(getFromSavedObject);
+ const [indexPattern] = indexPatternObjects.savedObjects.map(indexPatterns.getFromSavedObject);
return indexPattern;
}
const savedObject = await savedObjectsClient.get('index-pattern', defaultIndex);
- return getFromSavedObject(savedObject);
+ return indexPatterns.getFromSavedObject(savedObject);
}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
index 79acc189b6a29..7ab60f8867c38 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
@@ -313,7 +313,6 @@ export class VisualizeEmbeddable extends Embeddable {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index 15ad9a33232ef..7c9efa280c9f1 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -17,36 +17,48 @@
* under the License.
*/
+import 'uiExports/contextMenuActions';
+import 'uiExports/devTools';
+import 'uiExports/docViews';
+import 'uiExports/embeddableActions';
+import 'uiExports/fieldFormatEditors';
+import 'uiExports/fieldFormats';
+import 'uiExports/home';
+import 'uiExports/indexManagement';
+import 'uiExports/inspectorViews';
+import 'uiExports/savedObjectTypes';
+import 'uiExports/search';
+import 'uiExports/shareContextMenuExtensions';
+import 'uiExports/visTypes';
+import 'uiExports/visualize';
+
import { i18n } from '@kbn/i18n';
+import chrome from 'ui/chrome';
+import { npStart } from 'ui/new_platform';
+
import { Legacy } from 'kibana';
import { SavedObjectAttributes } from 'kibana/server';
+import {
+ EmbeddableFactory,
+ ErrorEmbeddable,
+ Container,
+ EmbeddableOutput,
+} from '../../../../../../plugins/embeddable/public';
+import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { showNewVisModal } from '../wizard';
import { SavedVisualizations } from '../types';
import { DisabledLabEmbeddable } from './disabled_lab_embeddable';
import { getIndexPattern } from './get_index_pattern';
-import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualize_embeddable';
-import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
-import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
-
import {
- getServices,
- Container,
- EmbeddableFactory,
- EmbeddableOutput,
- ErrorEmbeddable,
+ VisualizeEmbeddable,
+ VisualizeInput,
+ VisualizeOutput,
VisSavedObject,
-} from '../kibana_services';
-
-const {
- addBasePath,
- capabilities,
- embeddable,
- getInjector,
- uiSettings,
- visualizations,
-} = getServices();
+} from './visualize_embeddable';
+import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
+import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
interface VisualizationAttributes extends SavedObjectAttributes {
visState: string;
@@ -96,7 +108,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
if (!visType) {
return false;
}
- if (uiSettings.get('visualize:enableLabs')) {
+ if (npStart.core.uiSettings.get('visualize:enableLabs')) {
return true;
}
return visType.stage !== 'experimental';
@@ -108,7 +120,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
}
public isEditable() {
- return capabilities.visualize.save as boolean;
+ return npStart.core.application.capabilities.visualize.save as boolean;
}
public getDisplayName() {
@@ -122,14 +134,16 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
input: Partial & { id: string },
parent?: Container
): Promise {
- const $injector = await getInjector();
+ const $injector = await chrome.dangerouslyGetActiveInjector();
const config = $injector.get('config');
const savedVisualizations = $injector.get('savedVisualizations');
try {
const visId = savedObject.id as string;
- const editUrl = visId ? addBasePath(`/app/kibana${savedVisualizations.urlFor(visId)}`) : '';
+ const editUrl = visId
+ ? npStart.core.http.basePath.prepend(`/app/kibana${savedVisualizations.urlFor(visId)}`)
+ : '';
const isLabsEnabled = config.get('visualize:enableLabs');
if (!isLabsEnabled && savedObject.vis.type.stage === 'experimental') {
@@ -161,7 +175,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
input: Partial & { id: string },
parent?: Container
): Promise {
- const $injector = await getInjector();
+ const $injector = await chrome.dangerouslyGetActiveInjector();
const savedVisualizations = $injector.get('savedVisualizations');
try {
@@ -179,14 +193,15 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
// TODO: This is a bit of a hack to preserve the original functionality. Ideally we will clean this up
// to allow for in place creation of visualizations without having to navigate away to a new URL.
if (this.visTypes) {
- showNewVisModal(this.visTypes, {
- editorParams: ['addToDashboard'],
- });
+ showNewVisModal(
+ this.visTypes,
+ {
+ editorParams: ['addToDashboard'],
+ },
+ npStart.core.http.basePath.prepend,
+ npStart.core.uiSettings
+ );
}
return undefined;
}
}
-
-VisualizeEmbeddableFactory.createVisualizeEmbeddableFactory().then(embeddableFactory => {
- embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory);
-});
diff --git a/src/legacy/core_plugins/kibana/public/visualize/global_state_sync.ts b/src/legacy/core_plugins/kibana/public/visualize/global_state_sync.ts
new file mode 100644
index 0000000000000..71156bc38d498
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/global_state_sync.ts
@@ -0,0 +1,67 @@
+/*
+ * 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 { State } from './legacy_imports';
+import { DataPublicPluginStart as DataStart } from '../../../../../plugins/data/public';
+
+/**
+ * Helper function to sync the global state with the various state providers
+ * when a local angular application mounts. There are three different ways
+ * global state can be passed into the application:
+ * * parameter in the URL hash - e.g. shared link
+ * * in-memory state in the data plugin exports (timefilter and filterManager) - e.g. default values
+ *
+ * This function looks up the three sources (earlier in the list means it takes precedence),
+ * puts it into the globalState object and syncs it with the url.
+ *
+ * Currently the legacy chrome takes care of restoring the global state when navigating from
+ * one app to another - to migrate away from that it will become necessary to also write the current
+ * state to local storage
+ */
+export function syncOnMount(
+ globalState: State,
+ {
+ query: {
+ filterManager,
+ timefilter: { timefilter },
+ },
+ }: DataStart
+) {
+ // pull in global state information from the URL
+ globalState.fetch();
+ // remember whether there were info in the URL
+ const hasGlobalURLState = Boolean(Object.keys(globalState.toObject()).length);
+
+ // sync kibana platform state with the angular global state
+ if (!globalState.time) {
+ globalState.time = timefilter.getTime();
+ }
+ if (!globalState.refreshInterval) {
+ globalState.refreshInterval = timefilter.getRefreshInterval();
+ }
+ if (!globalState.filters && filterManager.getGlobalFilters().length > 0) {
+ globalState.filters = filterManager.getGlobalFilters();
+ }
+ // only inject cross app global state if there is none in the url itself (that takes precedence)
+ if (hasGlobalURLState) {
+ // set flag the global state is set from the URL
+ globalState.$inheritedGlobalState = true;
+ }
+ globalState.save();
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js b/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js
index d27003f39d4c0..9c00947d7663c 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js
@@ -18,10 +18,8 @@
*/
import { i18n } from '@kbn/i18n';
-import { getServices } from '../kibana_services';
-const { docLinks } = getServices();
-export function addHelpMenuToAppChrome(chrome) {
+export function addHelpMenuToAppChrome(chrome, docLinks) {
chrome.setHelpExtension({
appName: i18n.translate('kbn.visualize.helpMenu.appName', {
defaultMessage: 'Visualize',
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
deleted file mode 100644
index 57707f6321376..0000000000000
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { ensureDefaultIndexPattern } from 'ui/legacy_compat';
-import './editor/editor';
-import { i18n } from '@kbn/i18n';
-import './saved_visualizations/_saved_vis';
-import './saved_visualizations/saved_visualizations';
-import visualizeListingTemplate from './listing/visualize_listing.html';
-import { VisualizeListingController } from './listing/visualize_listing';
-import { VisualizeConstants } from './visualize_constants';
-import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs';
-
-import { getServices, FeatureCatalogueCategory } from './kibana_services';
-
-const { FeatureCatalogueRegistryProvider, uiRoutes } = getServices();
-
-uiRoutes
- .defaults(/visualize/, {
- requireUICapability: 'visualize.show',
- badge: uiCapabilities => {
- if (uiCapabilities.visualize.save) {
- return undefined;
- }
-
- return {
- text: i18n.translate('kbn.visualize.badge.readOnly.text', {
- defaultMessage: 'Read only',
- }),
- tooltip: i18n.translate('kbn.visualize.badge.readOnly.tooltip', {
- defaultMessage: 'Unable to save visualizations',
- }),
- iconType: 'glasses'
- };
- }
- })
- .when(VisualizeConstants.LANDING_PAGE_PATH, {
- template: visualizeListingTemplate,
- k7Breadcrumbs: getLandingBreadcrumbs,
- controller: VisualizeListingController,
- controllerAs: 'listingController',
- resolve: {
- createNewVis: () => false,
- hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(getServices().core, getServices().data, $rootScope, kbnUrl)
- },
- })
- .when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
- template: visualizeListingTemplate,
- k7Breadcrumbs: getWizardStep1Breadcrumbs,
- controller: VisualizeListingController,
- controllerAs: 'listingController',
- resolve: {
- createNewVis: () => true,
- hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(getServices().core, getServices().data, $rootScope, kbnUrl)
- },
- });
-
-FeatureCatalogueRegistryProvider.register(() => {
- return {
- id: 'visualize',
- title: 'Visualize',
- description: i18n.translate(
- 'kbn.visualize.visualizeDescription',
- {
- defaultMessage: 'Create visualizations and aggregate data stores in your Elasticsearch indices.',
- }
- ),
- icon: 'visualizeApp',
- path: `/app/kibana#${VisualizeConstants.LANDING_PAGE_PATH}`,
- showOnHomePage: true,
- category: FeatureCatalogueCategory.DATA
- };
-});
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.ts b/src/legacy/core_plugins/kibana/public/visualize/index.ts
new file mode 100644
index 0000000000000..5e9f2fdeb8999
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.ts
@@ -0,0 +1,70 @@
+/*
+ * 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 'ui/collapsible_sidebar'; // used in default editor
+import 'ui/vis/editors/default/sidebar';
+
+import {
+ IPrivate,
+ legacyChrome,
+ npSetup,
+ npStart,
+ SavedObjectRegistryProvider,
+ VisEditorTypesRegistryProvider,
+} from './legacy_imports';
+import { VisualizePlugin, LegacyAngularInjectedDependencies } from './plugin';
+import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy';
+import { start as navigation } from '../../../navigation/public/legacy';
+import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy';
+
+/**
+ * Get dependencies relying on the global angular context.
+ * They also have to get resolved together with the legacy imports above
+ */
+async function getAngularDependencies(): Promise {
+ const injector = await legacyChrome.dangerouslyGetActiveInjector();
+
+ const Private = injector.get('Private');
+
+ const editorTypes = Private(VisEditorTypesRegistryProvider);
+ const savedObjectRegistry = Private(SavedObjectRegistryProvider);
+
+ return {
+ legacyChrome,
+ editorTypes,
+ savedObjectRegistry,
+ savedVisualizations: injector.get('savedVisualizations'),
+ };
+}
+
+(() => {
+ const instance = new VisualizePlugin();
+ instance.setup(npSetup.core, {
+ ...npSetup.plugins,
+ __LEGACY: {
+ getAngularDependencies,
+ },
+ });
+ instance.start(npStart.core, {
+ ...npStart.plugins,
+ embeddables,
+ navigation,
+ visualizations,
+ });
+})();
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index 6477d1941c205..36a9ecf3fcf8c 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -17,108 +17,59 @@
* under the License.
*/
-import 'angular-sanitize'; // used in visualization_editor.js and visualization.js
-import 'ui/collapsible_sidebar'; // used in default editor
-import 'ui/vis/editors/default/sidebar';
-// load directives
-import '../../../data/public';
+import {
+ ChromeStart,
+ LegacyCoreStart,
+ SavedObjectsClientContract,
+ ToastsStart,
+ IUiSettingsClient,
+} from 'kibana/public';
-import { npStart } from 'ui/new_platform';
-import angular from 'angular'; // just used in editor.js
-import chromeLegacy from 'ui/chrome';
+import { NavigationStart } from '../../../navigation/public';
+import { Storage } from '../../../../../plugins/kibana_utils/public';
+import { IEmbeddableStart } from '../../../../../plugins/embeddable/public';
+import { SharePluginStart } from '../../../../../plugins/share/public';
+import { DataPublicPluginStart, IndexPatternsContract } from '../../../../../plugins/data/public';
+import { VisualizationsStart } from '../../../visualizations/public';
+import { SavedVisualizations } from './types';
-import uiRoutes from 'ui/routes';
-
-// @ts-ignore
-import { docTitle } from 'ui/doc_title';
-import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
-import { wrapInI18nContext } from 'ui/i18n';
-// @ts-ignore
-import { uiModules } from 'ui/modules';
-import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
-
-// Saved objects
-import { SavedObjectsClientProvider } from 'ui/saved_objects';
-// @ts-ignore
-import { SavedObject, SavedObjectProvider } from 'ui/saved_objects/saved_object';
-import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
-
-import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
-import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy';
-import { start as embeddables } from '../../../../core_plugins/embeddable_api/public/np_ready/public/legacy';
-import { start as data } from '../../../data/public/legacy';
-
-const services = {
- // new platform
- addBasePath: npStart.core.http.basePath.prepend,
- capabilities: npStart.core.application.capabilities,
- chrome: npStart.core.chrome,
- docLinks: npStart.core.docLinks,
- embeddable: npStart.plugins.embeddable,
- getBasePath: npStart.core.http.basePath.get,
- savedObjectsClient: npStart.core.savedObjects.client,
- toastNotifications: npStart.core.notifications.toasts,
- uiSettings: npStart.core.uiSettings,
- core: npStart.core,
-
- share: npStart.plugins.share,
- npData: npStart.plugins.data,
- data,
- embeddables,
- visualizations,
-
- // legacy
- chromeLegacy,
- docTitle,
- FeatureCatalogueRegistryProvider,
- FilterBarQueryFilterProvider,
- getInjector: () => {
- return chromeLegacy.dangerouslyGetActiveInjector();
- },
- SavedObjectProvider,
- SavedObjectRegistryProvider,
- SavedObjectsClientProvider,
- timefilter: npStart.plugins.data.query.timefilter.timefilter,
- uiModules,
- uiRoutes,
- wrapInI18nContext,
+export interface VisualizeKibanaServices {
+ addBasePath: (url: string) => string;
+ chrome: ChromeStart;
+ core: LegacyCoreStart;
+ data: DataPublicPluginStart;
+ editorTypes: any;
+ embeddables: IEmbeddableStart;
+ getBasePath: () => string;
+ indexPatterns: IndexPatternsContract;
+ legacyChrome: any;
+ localStorage: Storage;
+ navigation: NavigationStart;
+ toastNotifications: ToastsStart;
+ savedObjectsClient: SavedObjectsClientContract;
+ savedObjectRegistry: any;
+ savedQueryService: DataPublicPluginStart['query']['savedQueries'];
+ savedVisualizations: SavedVisualizations;
+ share: SharePluginStart;
+ uiSettings: IUiSettingsClient;
+ visualizeCapabilities: any;
+ visualizations: VisualizationsStart;
+}
- createUiStatsReporter,
-};
+let services: VisualizeKibanaServices | null = null;
+export function setServices(newServices: VisualizeKibanaServices) {
+ services = newServices;
+}
export function getServices() {
+ if (!services) {
+ throw new Error(
+ 'Kibana services not set - are you trying to import this module from outside of the visualize app?'
+ );
+ }
return services;
}
-// export legacy static dependencies
-export { angular };
-export { getFromSavedObject } from 'ui/index_patterns';
-export { PersistedState } from 'ui/persisted_state';
-// @ts-ignore
-export { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
-export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
-export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
-export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
-export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
-export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
-export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
-export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
-export { unhashUrl } from 'ui/state_management/state_hashing';
-export {
- Container,
- Embeddable,
- EmbeddableFactory,
- EmbeddableInput,
- EmbeddableOutput,
- ErrorEmbeddable,
-} from '../../../../../plugins/embeddable/public';
-
-// export types
-export { METRIC_TYPE };
-export { AppState } from 'ui/state_management/app_state';
-export { VisType } from 'ui/vis';
-
-// export const
-export { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
-
-export { VisSavedObject } from './embeddable/visualize_embeddable';
+export function clearServices() {
+ services = null;
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_app.js b/src/legacy/core_plugins/kibana/public/visualize/legacy_app.js
new file mode 100644
index 0000000000000..f47552e99a5c7
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_app.js
@@ -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 { find } from 'lodash';
+import { i18n } from '@kbn/i18n';
+
+import editorTemplate from './editor/editor.html';
+import visualizeListingTemplate from './listing/visualize_listing.html';
+
+import { initVisualizeAppDirective } from './visualize_app';
+import { VisualizeConstants } from './visualize_constants';
+import { VisualizeListingController } from './listing/visualize_listing';
+import { ensureDefaultIndexPattern, registerTimefilterWithGlobalStateFactory } from './legacy_imports';
+import { syncOnMount } from './global_state_sync';
+
+import {
+ getLandingBreadcrumbs,
+ getWizardStep1Breadcrumbs,
+ getCreateBreadcrumbs,
+ getEditBreadcrumbs
+} from './breadcrumbs';
+
+export function initVisualizeApp(app, deps) {
+ initVisualizeAppDirective(app, deps);
+
+ app.run(globalState => {
+ syncOnMount(globalState, deps.data);
+ });
+
+ app.run((globalState, $rootScope) => {
+ registerTimefilterWithGlobalStateFactory(
+ deps.data.query.timefilter.timefilter,
+ globalState,
+ $rootScope
+ );
+ });
+
+ app.config(function ($routeProvider) {
+ const defaults = {
+ reloadOnSearch: false,
+ requireUICapability: 'visualize.show',
+ badge: () => {
+ if (deps.visualizeCapabilities.save) {
+ return undefined;
+ }
+
+ return {
+ text: i18n.translate('kbn.visualize.badge.readOnly.text', {
+ defaultMessage: 'Read only',
+ }),
+ tooltip: i18n.translate('kbn.visualize.badge.readOnly.tooltip', {
+ defaultMessage: 'Unable to save visualizations',
+ }),
+ iconType: 'glasses',
+ };
+ },
+ };
+
+ $routeProvider
+ .when(VisualizeConstants.LANDING_PAGE_PATH, {
+ ...defaults,
+ template: visualizeListingTemplate,
+ k7Breadcrumbs: getLandingBreadcrumbs,
+ controller: VisualizeListingController,
+ controllerAs: 'listingController',
+ resolve: {
+ createNewVis: () => false,
+ hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl),
+ },
+ })
+ .when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
+ ...defaults,
+ template: visualizeListingTemplate,
+ k7Breadcrumbs: getWizardStep1Breadcrumbs,
+ controller: VisualizeListingController,
+ controllerAs: 'listingController',
+ resolve: {
+ createNewVis: () => true,
+ hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl),
+ },
+ })
+ .when(VisualizeConstants.CREATE_PATH, {
+ ...defaults,
+ template: editorTemplate,
+ k7Breadcrumbs: getCreateBreadcrumbs,
+ resolve: {
+ savedVis: function (redirectWhenMissing, $route, $rootScope, kbnUrl) {
+ const { core, data, savedVisualizations, visualizations } = deps;
+ const visTypes = visualizations.types.all();
+ const visType = find(visTypes, { name: $route.current.params.type });
+ const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection;
+ const hasIndex = $route.current.params.indexPattern || $route.current.params.savedSearchId;
+ if (shouldHaveIndex && !hasIndex) {
+ throw new Error(
+ i18n.translate('kbn.visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage', {
+ defaultMessage: 'You must provide either an indexPattern or a savedSearchId',
+ })
+ );
+ }
+
+ return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl).then(() => savedVisualizations.get($route.current.params))
+ .then(savedVis => {
+ if (savedVis.vis.type.setup) {
+ return savedVis.vis.type.setup(savedVis)
+ .catch(() => savedVis);
+ }
+ return savedVis;
+ })
+ .catch(redirectWhenMissing({
+ '*': '/visualize'
+ }));
+ }
+ }
+ })
+ .when(`${VisualizeConstants.EDIT_PATH}/:id`, {
+ ...defaults,
+ template: editorTemplate,
+ k7Breadcrumbs: getEditBreadcrumbs,
+ resolve: {
+ savedVis: function (redirectWhenMissing, $route, $rootScope, kbnUrl) {
+ const { chrome, core, data, savedVisualizations } = deps;
+ return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl)
+ .then(() => savedVisualizations.get($route.current.params.id))
+ .then(savedVis => {
+ chrome.recentlyAccessed.add(
+ savedVis.getFullPath(),
+ savedVis.title,
+ savedVis.id
+ );
+ return savedVis;
+ })
+ .then(savedVis => {
+ if (savedVis.vis.type.setup) {
+ return savedVis.vis.type.setup(savedVis).catch(() => savedVis);
+ }
+ return savedVis;
+ })
+ .catch(
+ redirectWhenMissing({
+ 'visualization': '/visualize',
+ 'search': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ 'index-pattern': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ 'index-pattern-field': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id
+ })
+ );
+ }
+ }
+ })
+ .when(`visualize/:tail*?`, {
+ redirectTo: `/${deps.core.injectedMetadata.getInjectedVar('kbnDefaultAppId')}`,
+ });
+ });
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
new file mode 100644
index 0000000000000..6adcfd2cc7186
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/**
+ * The imports in this file are static functions and types which still live in legacy folders and are used
+ * within dashboard. To consolidate them all in one place, they are re-exported from this file. Eventually
+ * this list should become empty. Imports from the top level of shimmed or moved plugins can be imported
+ * directly where they are needed.
+ */
+
+import chrome from 'ui/chrome';
+
+export const legacyChrome = chrome;
+
+// @ts-ignore
+export { AppState, AppStateProvider } from 'ui/state_management/app_state';
+export { State } from 'ui/state_management/state';
+// @ts-ignore
+export { GlobalStateProvider } from 'ui/state_management/global_state';
+// @ts-ignore
+export { StateManagementConfigProvider } from 'ui/state_management/config_provider';
+export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
+export { PersistedState } from 'ui/persisted_state';
+
+export { npSetup, npStart } from 'ui/new_platform';
+export { IPrivate } from 'ui/private';
+// @ts-ignore
+export { PrivateProvider } from 'ui/private/private';
+
+export { SavedObjectRegistryProvider } from 'ui/saved_objects';
+export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
+export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
+export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
+
+export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
+export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
+// @ts-ignore
+export { EventsProvider } from 'ui/events';
+// @ts-ignore
+export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav';
+// @ts-ignore
+export { PromiseServiceCreator } from 'ui/promises/promises';
+// @ts-ignore
+export { confirmModalFactory } from 'ui/modals/confirm_modal';
+export { configureAppAngularModule, ensureDefaultIndexPattern } from 'ui/legacy_compat';
+export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
+// @ts-ignore
+export { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
+
+// @ts-ignore
+export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
+export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
+export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
+
+// @ts-ignore
+export { defaultEditor } from 'ui/vis/editors/default/default';
+export { VisType } from 'ui/vis';
+export { wrapInI18nContext } from 'ui/i18n';
+
+export { VisSavedObject } from './embeddable/visualize_embeddable';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html
index edb7cccbd46a2..4511ac61f7396 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html
@@ -14,6 +14,8 @@
is-open="listingController.showNewVisModal"
on-close="listingController.closeNewVisModal"
vis-types-registry="listingController.visTypeRegistry"
+ add-base-path="listingController.addBasePath"
+ ui-settings="listingController.uiSettings"
>
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index f9e3a1a90115a..9b02be0581b8d 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -24,36 +24,46 @@ import { VisualizeConstants } from '../visualize_constants';
import { i18n } from '@kbn/i18n';
import { getServices } from '../kibana_services';
-
-const {
- addBasePath,
- chrome,
- chromeLegacy,
- SavedObjectRegistryProvider,
- SavedObjectsClientProvider,
- timefilter,
- toastNotifications,
- uiModules,
- wrapInI18nContext,
- visualizations,
-} = getServices();
-
-const app = uiModules.get('app/visualize', ['ngRoute', 'react']);
-app.directive('visualizeListingTable', reactDirective =>
- reactDirective(wrapInI18nContext(VisualizeListingTable))
-);
-app.directive('newVisModal', reactDirective => reactDirective(wrapInI18nContext(NewVisModal)));
+import { wrapInI18nContext } from '../legacy_imports';
+
+export function initListingDirective(app) {
+ app.directive('visualizeListingTable', reactDirective => reactDirective(wrapInI18nContext(VisualizeListingTable)));
+ app.directive('newVisModal', reactDirective =>
+ reactDirective(wrapInI18nContext(NewVisModal), [
+ ['visTypesRegistry', { watchDepth: 'collection' }],
+ ['onClose', { watchDepth: 'reference' }],
+ ['addBasePath', { watchDepth: 'reference' }],
+ ['uiSettings', { watchDepth: 'reference' }],
+ 'isOpen',
+ ])
+ );
+}
export function VisualizeListingController($injector, createNewVis) {
- const Private = $injector.get('Private');
- const config = $injector.get('config');
+ const {
+ addBasePath,
+ chrome,
+ legacyChrome,
+ savedObjectRegistry,
+ savedObjectsClient,
+ data: {
+ query: {
+ timefilter: { timefilter },
+ },
+ },
+ toastNotifications,
+ uiSettings,
+ visualizations,
+ core: { docLinks },
+ } = getServices();
const kbnUrl = $injector.get('kbnUrl');
- const savedObjectClient = Private(SavedObjectsClientProvider);
timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();
this.showNewVisModal = false;
+ this.addBasePath = addBasePath;
+ this.uiSettings = uiSettings;
this.createNewVis = () => {
this.showNewVisModal = true;
@@ -82,14 +92,14 @@ export function VisualizeListingController($injector, createNewVis) {
}
// TODO: Extract this into an external service.
- const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName;
+ const services = savedObjectRegistry.byLoaderPropertiesName;
const visualizationService = services.visualizations;
this.visTypeRegistry = visualizations.types;
this.fetchItems = filter => {
- const isLabsEnabled = config.get('visualize:enableLabs');
+ const isLabsEnabled = uiSettings.get('visualize:enableLabs');
return visualizationService
- .findListItems(filter, config.get('savedObjects:listingLimit'))
+ .findListItems(filter, uiSettings.get('savedObjects:listingLimit'))
.then(result => {
this.totalItems = result.total;
@@ -103,11 +113,11 @@ export function VisualizeListingController($injector, createNewVis) {
this.deleteSelectedItems = function deleteSelectedItems(selectedItems) {
return Promise.all(
selectedItems.map(item => {
- return savedObjectClient.delete(item.savedObjectType, item.id);
+ return savedObjectsClient.delete(item.savedObjectType, item.id);
})
)
.then(() => {
- chromeLegacy.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id));
+ legacyChrome.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id));
})
.catch(error => {
toastNotifications.addError(error, {
@@ -126,7 +136,7 @@ export function VisualizeListingController($injector, createNewVis) {
},
]);
- this.listingLimit = config.get('savedObjects:listingLimit');
+ this.listingLimit = uiSettings.get('savedObjects:listingLimit');
- addHelpMenuToAppChrome(chrome);
+ addHelpMenuToAppChrome(chrome, docLinks);
}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
index efab03303aa80..890fa64af9693 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
@@ -27,22 +27,21 @@ import { EuiIcon, EuiBetaBadge, EuiLink, EuiButton, EuiEmptyPrompt } from '@elas
import { getServices } from '../kibana_services';
-const { capabilities, toastNotifications, uiSettings } = getServices();
-
class VisualizeListingTable extends Component {
constructor(props) {
super(props);
}
render() {
+ const { visualizeCapabilities, uiSettings, toastNotifications } = getServices();
return (
item.canDelete}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts
new file mode 100644
index 0000000000000..1aa2d70dabea6
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts
@@ -0,0 +1,161 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+import {
+ CoreSetup,
+ CoreStart,
+ LegacyCoreStart,
+ Plugin,
+ SavedObjectsClientContract,
+} from 'kibana/public';
+
+import { Storage } from '../../../../../plugins/kibana_utils/public';
+import { DataPublicPluginStart } from '../../../../../plugins/data/public';
+import { IEmbeddableStart } from '../../../../../plugins/embeddable/public';
+import { NavigationStart } from '../../../navigation/public';
+import { SharePluginStart } from '../../../../../plugins/share/public';
+import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public';
+import { VisualizationsStart } from '../../../visualizations/public';
+import { VisualizeEmbeddableFactory } from './embeddable/visualize_embeddable_factory';
+import { VISUALIZE_EMBEDDABLE_TYPE } from './embeddable/constants';
+import { VisualizeConstants } from './visualize_constants';
+import { setServices, VisualizeKibanaServices } from './kibana_services';
+import {
+ FeatureCatalogueCategory,
+ HomePublicPluginSetup,
+} from '../../../../../plugins/home/public';
+import { defaultEditor, VisEditorTypesRegistryProvider } from './legacy_imports';
+import { SavedVisualizations } from './types';
+
+export interface LegacyAngularInjectedDependencies {
+ legacyChrome: any;
+ editorTypes: any;
+ savedObjectRegistry: any;
+ savedVisualizations: SavedVisualizations;
+}
+
+export interface VisualizePluginStartDependencies {
+ data: DataPublicPluginStart;
+ embeddables: IEmbeddableStart;
+ navigation: NavigationStart;
+ share: SharePluginStart;
+ visualizations: VisualizationsStart;
+}
+
+export interface VisualizePluginSetupDependencies {
+ __LEGACY: {
+ getAngularDependencies: () => Promise;
+ };
+ home: HomePublicPluginSetup;
+ kibana_legacy: KibanaLegacySetup;
+}
+
+export class VisualizePlugin implements Plugin {
+ private startDependencies: {
+ data: DataPublicPluginStart;
+ embeddables: IEmbeddableStart;
+ navigation: NavigationStart;
+ savedObjectsClient: SavedObjectsClientContract;
+ share: SharePluginStart;
+ visualizations: VisualizationsStart;
+ } | null = null;
+
+ public async setup(
+ core: CoreSetup,
+ { home, kibana_legacy, __LEGACY: { getAngularDependencies } }: VisualizePluginSetupDependencies
+ ) {
+ kibana_legacy.registerLegacyApp({
+ id: 'visualize',
+ title: 'Visualize',
+ mount: async ({ core: contextCore }, params) => {
+ if (this.startDependencies === null) {
+ throw new Error('not started yet');
+ }
+
+ const {
+ savedObjectsClient,
+ embeddables,
+ navigation,
+ visualizations,
+ data,
+ share,
+ } = this.startDependencies;
+
+ const angularDependencies = await getAngularDependencies();
+ const deps: VisualizeKibanaServices = {
+ ...angularDependencies,
+ addBasePath: contextCore.http.basePath.prepend,
+ core: contextCore as LegacyCoreStart,
+ chrome: contextCore.chrome,
+ data,
+ embeddables,
+ getBasePath: core.http.basePath.get,
+ indexPatterns: data.indexPatterns,
+ localStorage: new Storage(localStorage),
+ navigation,
+ savedObjectsClient,
+ savedQueryService: data.query.savedQueries,
+ share,
+ toastNotifications: contextCore.notifications.toasts,
+ uiSettings: contextCore.uiSettings,
+ visualizeCapabilities: contextCore.application.capabilities.visualize,
+ visualizations,
+ };
+ setServices(deps);
+
+ const { renderApp } = await import('./application');
+ return renderApp(params.element, params.appBasePath, deps);
+ },
+ });
+
+ home.featureCatalogue.register({
+ id: 'visualize',
+ title: 'Visualize',
+ description: i18n.translate('kbn.visualize.visualizeDescription', {
+ defaultMessage:
+ 'Create visualizations and aggregate data stores in your Elasticsearch indices.',
+ }),
+ icon: 'visualizeApp',
+ path: `/app/kibana#${VisualizeConstants.LANDING_PAGE_PATH}`,
+ showOnHomePage: true,
+ category: FeatureCatalogueCategory.DATA,
+ });
+
+ VisEditorTypesRegistryProvider.register(defaultEditor);
+ }
+
+ public start(
+ { savedObjects: { client: savedObjectsClient } }: CoreStart,
+ { embeddables, navigation, data, share, visualizations }: VisualizePluginStartDependencies
+ ) {
+ this.startDependencies = {
+ data,
+ embeddables,
+ navigation,
+ savedObjectsClient,
+ share,
+ visualizations,
+ };
+
+ const embeddableFactory = new VisualizeEmbeddableFactory(visualizations.types);
+ embeddables.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory);
+ }
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/types.d.ts b/src/legacy/core_plugins/kibana/public/visualize/types.d.ts
index c83f7f5a5da8b..b6a3981215384 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/types.d.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/types.d.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { VisSavedObject } from './kibana_services';
+import { VisSavedObject } from './legacy_imports';
export interface SavedVisualizations {
urlFor: (id: string) => string;
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_directive.ts b/src/legacy/core_plugins/kibana/public/visualize/visualize_app.ts
similarity index 67%
rename from src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_directive.ts
rename to src/legacy/core_plugins/kibana/public/visualize/visualize_app.ts
index 5ebefd817ca4a..c64287a0e63b8 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_directive.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/visualize_app.ts
@@ -16,15 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
+
+import { IModule } from 'angular';
+import { VisualizeKibanaServices } from './kibana_services';
+
+// @ts-ignore
+import { initEditorDirective } from './editor/editor';
// @ts-ignore
-import angular from 'angular';
-import { DashboardEmptyScreen } from './dashboard_empty_screen';
+import { initListingDirective } from './listing/visualize_listing';
-angular
- .module('app/dashboard/emptyScreen', ['react'])
- .directive('dashboardEmptyScreen', function(reactDirective: any) {
- return reactDirective(DashboardEmptyScreen, [
- ['showLinkToVisualize', { watchDepth: 'value' }],
- ['onLinkClick', { watchDepth: 'reference' }],
- ]);
- });
+export function initVisualizeAppDirective(app: IModule, deps: VisualizeKibanaServices) {
+ initEditorDirective(app, deps);
+ initListingDirective(app);
+}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap
index 4aa614b68ea23..5be5f58994887 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap
@@ -2,6 +2,7 @@
exports[`NewVisModal filter for visualization types should render as expected 1`] = `
@@ -1287,6 +1307,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
exports[`NewVisModal should render as expected 1`] = `
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
index 99d9590e750fd..0dd2091bbfee0 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
@@ -20,33 +20,17 @@
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { NewVisModal } from './new_vis_modal';
-import { VisType } from '../kibana_services';
+import { VisType } from '../legacy_imports';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
-jest.mock('../kibana_services', () => {
- const mock = {
- addBasePath: jest.fn(path => `root${path}`),
- uiSettings: { get: jest.fn() },
- createUiStatsReporter: () => jest.fn(),
- };
-
- return {
- getServices: () => mock,
- VisType: {},
- METRIC_TYPE: 'metricType',
- };
-});
-
-import { getServices } from '../kibana_services';
+jest.mock('../legacy_imports', () => ({
+ State: () => null,
+ AppState: () => null,
+}));
-beforeEach(() => {
- jest.clearAllMocks();
-});
+import { NewVisModal } from './new_vis_modal';
describe('NewVisModal', () => {
- const settingsGet = getServices().uiSettings.get as jest.Mock;
-
const defaultVisTypeParams = {
hidden: false,
visualization: class Controller {
@@ -76,17 +60,36 @@ describe('NewVisModal', () => {
},
getAliases: () => [],
};
+ const addBasePath = (url: string) => `testbasepath${url}`;
+ const settingsGet = jest.fn();
+ const uiSettings: any = { get: settingsGet };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
it('should render as expected', () => {
const wrapper = mountWithIntl(
- null} visTypesRegistry={visTypes} />
+ null}
+ visTypesRegistry={visTypes}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
+ />
);
expect(wrapper).toMatchSnapshot();
});
it('should show a button for regular visualizations', () => {
const wrapper = mountWithIntl(
- null} visTypesRegistry={visTypes} />
+ null}
+ visTypesRegistry={visTypes}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
+ />
);
expect(wrapper.find('[data-test-subj="visType-vis"]').exists()).toBe(true);
});
@@ -95,7 +98,13 @@ describe('NewVisModal', () => {
it('should open the editor for visualizations without search', () => {
window.location.assign = jest.fn();
const wrapper = mountWithIntl(
- null} visTypesRegistry={visTypes} />
+ null}
+ visTypesRegistry={visTypes}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
+ />
);
const visButton = wrapper.find('button[data-test-subj="visType-vis"]');
visButton.simulate('click');
@@ -110,6 +119,8 @@ describe('NewVisModal', () => {
onClose={() => null}
visTypesRegistry={visTypes}
editorParams={['foo=true', 'bar=42']}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
/>
);
const visButton = wrapper.find('button[data-test-subj="visType-vis"]');
@@ -121,7 +132,13 @@ describe('NewVisModal', () => {
describe('filter for visualization types', () => {
it('should render as expected', () => {
const wrapper = mountWithIntl(
- null} visTypesRegistry={visTypes} />
+ null}
+ visTypesRegistry={visTypes}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
+ />
);
const searchBox = wrapper.find('input[data-test-subj="filterVisType"]');
searchBox.simulate('change', { target: { value: 'with' } });
@@ -133,7 +150,13 @@ describe('NewVisModal', () => {
it('should not show experimental visualizations if visualize:enableLabs is false', () => {
settingsGet.mockReturnValue(false);
const wrapper = mountWithIntl(
- null} visTypesRegistry={visTypes} />
+ null}
+ visTypesRegistry={visTypes}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
+ />
);
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(false);
});
@@ -141,7 +164,13 @@ describe('NewVisModal', () => {
it('should show experimental visualizations if visualize:enableLabs is true', () => {
settingsGet.mockReturnValue(true);
const wrapper = mountWithIntl(
- null} visTypesRegistry={visTypes} />
+ null}
+ visTypesRegistry={visTypes}
+ addBasePath={addBasePath}
+ uiSettings={uiSettings}
+ />
);
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(true);
});
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
index 420f0e5198056..0b46b562f2146 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
@@ -22,20 +22,21 @@ import React from 'react';
import { EuiModal, EuiOverlayMask } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { IUiSettingsClient } from 'kibana/public';
+import { VisType } from '../legacy_imports';
import { VisualizeConstants } from '../visualize_constants';
+import { createUiStatsReporter, METRIC_TYPE } from '../../../../ui_metric/public';
import { SearchSelection } from './search_selection';
import { TypeSelection } from './type_selection';
import { TypesStart, VisTypeAlias } from '../../../../visualizations/public/np_ready/public/types';
-import { getServices, METRIC_TYPE, VisType } from '../kibana_services';
-
-const { addBasePath, createUiStatsReporter, uiSettings } = getServices();
-
interface TypeSelectionProps {
isOpen: boolean;
onClose: () => void;
visTypesRegistry: TypesStart;
editorParams?: string[];
+ addBasePath: (path: string) => string;
+ uiSettings: IUiSettingsClient;
}
interface TypeSelectionState {
@@ -55,7 +56,7 @@ class NewVisModal extends React.Component
);
@@ -124,7 +126,7 @@ class NewVisModal extends React.Component void;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx
index fa2ca6747bc40..92320f7bb443a 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx
@@ -20,7 +20,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import { I18nContext } from 'ui/i18n';
+import { I18nProvider } from '@kbn/i18n/react';
+import { IUiSettingsClient } from 'kibana/public';
import { NewVisModal } from './new_vis_modal';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
@@ -30,7 +31,9 @@ interface ShowNewVisModalParams {
export function showNewVisModal(
visTypeRegistry: TypesStart,
- { editorParams = [] }: ShowNewVisModalParams = {}
+ { editorParams = [] }: ShowNewVisModalParams = {},
+ addBasePath: (path: string) => string,
+ uiSettings: IUiSettingsClient
) {
const container = document.createElement('div');
const onClose = () => {
@@ -40,14 +43,16 @@ export function showNewVisModal(
document.body.appendChild(container);
const element = (
-
+
-
+
);
ReactDOM.render(element, container);
}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
index 382f475669f5d..3093499a030c8 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
@@ -21,18 +21,6 @@ import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { NewVisHelp } from './new_vis_help';
-jest.mock('../../kibana_services', () => {
- return {
- getServices: () => ({
- addBasePath: jest.fn((url: string) => `testbasepath${url}`),
- }),
- };
-});
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
describe('NewVisHelp', () => {
it('should render as expected', () => {
expect(
@@ -53,6 +41,7 @@ describe('NewVisHelp', () => {
stage: 'production',
},
]}
+ addBasePath={(url: string) => `testbasepath${url}`}
/>
)
).toMatchInlineSnapshot(`
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.tsx
index 44c36f7d17d55..107cbc0e754b5 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.tsx
@@ -22,10 +22,9 @@ import React, { Fragment } from 'react';
import { EuiText, EuiButton } from '@elastic/eui';
import { VisTypeAliasListEntry } from './type_selection';
-import { getServices } from '../../kibana_services';
-
interface Props {
promotedTypes: VisTypeAliasListEntry[];
+ addBasePath: (path: string) => string;
}
export function NewVisHelp(props: Props) {
@@ -43,7 +42,7 @@ export function NewVisHelp(props: Props) {
{t.promotion!.description}
string;
onVisTypeSelected: (visType: VisType | VisTypeAlias) => void;
visTypesRegistry: TypesStart;
showExperimental: boolean;
@@ -153,6 +154,7 @@ class TypeSelection extends React.Component
t.promotion)}
+ addBasePath={this.props.addBasePath}
/>
)}
diff --git a/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js b/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js
index 4ffe790bd51a1..1f5ed443fee80 100644
--- a/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js
+++ b/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js
@@ -18,6 +18,7 @@
*/
import { get, map } from 'lodash';
+import { abortableRequestHandler } from '../../../../../elasticsearch/lib/abortable_request_handler';
export function registerValueSuggestions(server) {
const serverConfig = server.config();
@@ -26,7 +27,7 @@ export function registerValueSuggestions(server) {
server.route({
path: '/api/kibana/suggestions/values/{index}',
method: ['POST'],
- handler: async function (req) {
+ handler: abortableRequestHandler(async function (signal, req) {
const { index } = req.params;
const { field: fieldName, query, boolFilter } = req.payload;
const { callWithRequest } = server.plugins.elasticsearch.getCluster('data');
@@ -46,7 +47,7 @@ export function registerValueSuggestions(server) {
);
try {
- const response = await callWithRequest(req, 'search', { index, body });
+ const response = await callWithRequest(req, 'search', { index, body }, { signal });
const buckets = get(response, 'aggregations.suggestions.buckets')
|| get(response, 'aggregations.nestedSuggestions.suggestions.buckets')
|| [];
@@ -55,7 +56,7 @@ export function registerValueSuggestions(server) {
} catch (error) {
throw server.plugins.elasticsearch.handleESError(error);
}
- },
+ }),
});
}
diff --git a/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json b/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json
index 69a165c09c2f9..9001613623ccb 100644
--- a/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json
+++ b/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json
@@ -1,7 +1,7 @@
{
"attributes": {
"fieldFormatMap": "{\"client.bytes\":{\"id\":\"bytes\"},\"client.nat.port\":{\"id\":\"string\"},\"client.port\":{\"id\":\"string\"},\"destination.bytes\":{\"id\":\"bytes\"},\"destination.nat.port\":{\"id\":\"string\"},\"destination.port\":{\"id\":\"string\"},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"},\"http.request.body.bytes\":{\"id\":\"bytes\"},\"http.request.bytes\":{\"id\":\"bytes\"},\"http.response.body.bytes\":{\"id\":\"bytes\"},\"http.response.bytes\":{\"id\":\"bytes\"},\"http.response.status_code\":{\"id\":\"string\"},\"log.syslog.facility.code\":{\"id\":\"string\"},\"log.syslog.priority\":{\"id\":\"string\"},\"network.bytes\":{\"id\":\"bytes\"},\"package.size\":{\"id\":\"string\"},\"process.pgid\":{\"id\":\"string\"},\"process.pid\":{\"id\":\"string\"},\"process.ppid\":{\"id\":\"string\"},\"process.thread.id\":{\"id\":\"string\"},\"server.bytes\":{\"id\":\"bytes\"},\"server.nat.port\":{\"id\":\"string\"},\"server.port\":{\"id\":\"string\"},\"source.bytes\":{\"id\":\"bytes\"},\"source.nat.port\":{\"id\":\"string\"},\"source.port\":{\"id\":\"string\"},\"system.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.memory.actual.free\":{\"id\":\"bytes\"},\"system.memory.total\":{\"id\":\"bytes\"},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\"},\"system.process.memory.size\":{\"id\":\"bytes\"},\"url.port\":{\"id\":\"string\"},\"view spans\":{\"id\":\"url\",\"params\":{\"labelTemplate\":\"View Spans\"}}}",
- "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]",
+ "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]",
"sourceFilters": "[{\"value\":\"sourcemap.sourcemap\"}]",
"timeFieldName": "@timestamp"
},
diff --git a/src/legacy/core_plugins/management/index.ts b/src/legacy/core_plugins/management/index.ts
new file mode 100644
index 0000000000000..65601b5371815
--- /dev/null
+++ b/src/legacy/core_plugins/management/index.ts
@@ -0,0 +1,37 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { resolve } from 'path';
+import { Legacy } from '../../../../kibana';
+
+// eslint-disable-next-line import/no-default-export
+export default function ManagementPlugin(kibana: any) {
+ const config: Legacy.PluginSpecOptions = {
+ id: 'management',
+ publicDir: resolve(__dirname, 'public'),
+ config: (Joi: any) => {
+ return Joi.object({
+ enabled: Joi.boolean().default(true),
+ }).default();
+ },
+ init: (server: Legacy.Server) => ({}),
+ };
+
+ return new kibana.Plugin(config);
+}
diff --git a/src/legacy/core_plugins/management/package.json b/src/legacy/core_plugins/management/package.json
new file mode 100644
index 0000000000000..77d33a7bce3b6
--- /dev/null
+++ b/src/legacy/core_plugins/management/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "management",
+ "version": "kibana"
+}
+
\ No newline at end of file
diff --git a/src/legacy/ui/public/management/saved_objects_management/index.ts b/src/legacy/core_plugins/management/public/index.ts
similarity index 72%
rename from src/legacy/ui/public/management/saved_objects_management/index.ts
rename to src/legacy/core_plugins/management/public/index.ts
index c7223a859ee37..3d64b6d2aa2bb 100644
--- a/src/legacy/ui/public/management/saved_objects_management/index.ts
+++ b/src/legacy/core_plugins/management/public/index.ts
@@ -17,13 +17,24 @@
* under the License.
*/
-export { SavedObjectsManagementActionRegistry } from './saved_objects_management_action_registry';
+/**
+ * Static np-ready code, re-exported here so consumers can import from
+ * `src/legacy/core_plugins/management/public`
+ *
+ * @public
+ */
+
export {
+ ManagementSetup,
+ ManagementStart,
+ plugin,
+ IndexPatternCreationConfig,
+ IndexPatternListConfig,
SavedObjectsManagementAction,
SavedObjectsManagementRecord,
- SavedObjectsManagementRecordReference,
-} from './saved_objects_management_action';
+} from './np_ready';
+
export {
processImportResponse,
ProcessedImportResponse,
-} from '../../../../core_plugins/kibana/public/management/sections/objects/lib/process_import_response';
+} from '../../kibana/public/management/sections/objects/lib/process_import_response';
diff --git a/src/legacy/core_plugins/management/public/legacy.ts b/src/legacy/core_plugins/management/public/legacy.ts
new file mode 100644
index 0000000000000..7c17f0c6bddc0
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/legacy.ts
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/**
+ * New Platform Shim
+ *
+ * In this file, we import any legacy dependencies we have, and shim them into
+ * our plugin by manually constructing the values that the new platform will
+ * eventually be passing to the `setup/start` method of our plugin definition.
+ *
+ * The idea is that our `plugin.ts` can stay "pure" and not contain any legacy
+ * world code. Then when it comes time to migrate to the new platform, we can
+ * simply delete this shim file.
+ *
+ * We are also calling `setup/start` here and exporting our public contract so that
+ * other legacy plugins are able to import from '../core_plugins/visualizations/legacy'
+ * and receive the response value of the `setup/start` contract, mimicking the
+ * data that will eventually be injected by the new platform.
+ */
+
+import { PluginInitializerContext } from 'src/core/public';
+import { npSetup, npStart } from 'ui/new_platform';
+
+import { plugin } from '.';
+
+const pluginInstance = plugin({} as PluginInitializerContext);
+
+export const setup = pluginInstance.setup(npSetup.core, {});
+export const start = pluginInstance.start(npStart.core, {});
diff --git a/src/legacy/core_plugins/management/public/np_ready/index.ts b/src/legacy/core_plugins/management/public/np_ready/index.ts
new file mode 100644
index 0000000000000..ec93516df8349
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/index.ts
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/**
+ * Management Plugin - public
+ *
+ * This is the entry point for the entire client-side public contract of the plugin.
+ * If something is not explicitly exported here, you can safely assume it is private
+ * to the plugin and not considered stable.
+ *
+ * All stateful contracts will be injected by the platform at runtime, and are defined
+ * in the setup/start interfaces in `plugin.ts`. The remaining items exported here are
+ * either types, or static code.
+ */
+import { PluginInitializerContext } from 'src/core/public';
+import { ManagementPlugin } from './plugin';
+export { ManagementSetup, ManagementStart } from './plugin';
+
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new ManagementPlugin(initializerContext);
+}
+
+export {
+ IndexPatternCreationConfig,
+ IndexPatternListConfig,
+} from './services/index_pattern_management';
+
+export {
+ SavedObjectsManagementAction,
+ SavedObjectsManagementRecord,
+} from './services/saved_objects_management';
diff --git a/src/legacy/core_plugins/management/public/np_ready/mocks.ts b/src/legacy/core_plugins/management/public/np_ready/mocks.ts
new file mode 100644
index 0000000000000..13a0cf4c891a3
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/mocks.ts
@@ -0,0 +1,66 @@
+/*
+ * 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 { PluginInitializerContext } from 'src/core/public';
+import { coreMock } from '../../../../../core/public/mocks';
+import { ManagementSetup, ManagementStart, ManagementPlugin } from './plugin';
+
+const createSetupContract = (): ManagementSetup => ({
+ indexPattern: {
+ creation: {
+ add: jest.fn(),
+ getType: jest.fn(),
+ getIndexPatternCreationOptions: jest.fn(),
+ } as any,
+ list: {
+ add: jest.fn(),
+ getIndexPatternTags: jest.fn(),
+ getFieldInfo: jest.fn(),
+ areScriptedFieldsEnabled: jest.fn(),
+ } as any,
+ },
+ savedObjects: {
+ registry: {
+ register: jest.fn(),
+ has: jest.fn(),
+ get: jest.fn(() => []),
+ },
+ },
+});
+
+const createStartContract = (): ManagementStart => ({});
+
+const createInstance = async () => {
+ const plugin = new ManagementPlugin({} as PluginInitializerContext);
+
+ const setup = plugin.setup(coreMock.createSetup(), {});
+ const doStart = () => plugin.start(coreMock.createStart(), {});
+
+ return {
+ plugin,
+ setup,
+ doStart,
+ };
+};
+
+export const mockManagementPlugin = {
+ createSetupContract,
+ createStartContract,
+ createInstance,
+};
diff --git a/src/legacy/core_plugins/management/public/np_ready/plugin.ts b/src/legacy/core_plugins/management/public/np_ready/plugin.ts
new file mode 100644
index 0000000000000..032a46439ba55
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/plugin.ts
@@ -0,0 +1,67 @@
+/*
+ * 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
+import { IndexPatternManagementService, IndexPatternManagementSetup } from './services';
+import {
+ SavedObjectsManagementService,
+ SavedObjectsManagementServiceSetup,
+} from './services/saved_objects_management';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+interface ManagementPluginSetupDependencies {}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+interface ManagementPluginStartDependencies {}
+
+export interface ManagementSetup {
+ indexPattern: IndexPatternManagementSetup;
+ savedObjects: SavedObjectsManagementServiceSetup;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface ManagementStart {}
+
+export class ManagementPlugin
+ implements
+ Plugin<
+ ManagementSetup,
+ ManagementStart,
+ ManagementPluginSetupDependencies,
+ ManagementPluginStartDependencies
+ > {
+ private readonly indexPattern = new IndexPatternManagementService();
+ private readonly savedObjects = new SavedObjectsManagementService();
+
+ constructor(initializerContext: PluginInitializerContext) {}
+
+ public setup(core: CoreSetup, deps: ManagementPluginSetupDependencies) {
+ return {
+ indexPattern: this.indexPattern.setup({ httpClient: core.http }),
+ savedObjects: this.savedObjects.setup(),
+ };
+ }
+
+ public start(core: CoreStart, plugins: ManagementPluginStartDependencies) {
+ return {};
+ }
+
+ public stop() {
+ this.indexPattern.stop();
+ }
+}
diff --git a/src/legacy/ui/public/state_management/state_hashing/index.ts b/src/legacy/core_plugins/management/public/np_ready/services/index.ts
similarity index 85%
rename from src/legacy/ui/public/state_management/state_hashing/index.ts
rename to src/legacy/core_plugins/management/public/np_ready/services/index.ts
index 6225202f90978..4d55fce3d8a7d 100644
--- a/src/legacy/ui/public/state_management/state_hashing/index.ts
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index.ts
@@ -17,5 +17,5 @@
* under the License.
*/
-export { hashUrl, unhashUrl, hashQuery, unhashQuery } from './hash_unhash_url';
-export { createStateHash, isStateHash } from './state_hash';
+export * from './index_pattern_management';
+export * from './saved_objects_management';
diff --git a/src/legacy/ui/public/management/index_pattern_creation/index_pattern_creation_config.js b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts
similarity index 55%
rename from src/legacy/ui/public/management/index_pattern_creation/index_pattern_creation_config.js
rename to src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts
index 9cf1e6c4ed373..0598c88c80ba7 100644
--- a/src/legacy/ui/public/management/index_pattern_creation/index_pattern_creation_config.js
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts
@@ -19,17 +19,39 @@
import { i18n } from '@kbn/i18n';
-const indexPatternTypeName = i18n.translate('common.ui.management.editIndexPattern.createIndex.defaultTypeName',
- { defaultMessage: 'index pattern' });
-
-const indexPatternButtonText = i18n.translate('common.ui.management.editIndexPattern.createIndex.defaultButtonText',
- { defaultMessage: 'Standard index pattern' });
-
-const indexPatternButtonDescription = i18n.translate('common.ui.management.editIndexPattern.createIndex.defaultButtonDescription',
- { defaultMessage: 'Perform full aggregations against any data' });
+const indexPatternTypeName = i18n.translate(
+ 'management.editIndexPattern.createIndex.defaultTypeName',
+ { defaultMessage: 'index pattern' }
+);
+
+const indexPatternButtonText = i18n.translate(
+ 'management.editIndexPattern.createIndex.defaultButtonText',
+ { defaultMessage: 'Standard index pattern' }
+);
+
+const indexPatternButtonDescription = i18n.translate(
+ 'management.editIndexPattern.createIndex.defaultButtonDescription',
+ { defaultMessage: 'Perform full aggregations against any data' }
+);
+
+export type UrlHandler = (url: string) => void;
+
+export interface IndexPatternCreationOption {
+ text: string;
+ description: string;
+ testSubj: string;
+ onClick: () => void;
+ isBeta?: boolean;
+}
export class IndexPatternCreationConfig {
- static key = 'default';
+ public readonly key = 'default';
+
+ protected type?: string;
+ protected name: string;
+ protected showSystemIndices: boolean;
+ protected httpClient: object | null;
+ protected isBeta: boolean;
constructor({
type = undefined,
@@ -37,6 +59,12 @@ export class IndexPatternCreationConfig {
showSystemIndices = true,
httpClient = null,
isBeta = false,
+ }: {
+ type?: string;
+ name?: string;
+ showSystemIndices?: boolean;
+ httpClient?: object | null;
+ isBeta?: boolean;
}) {
this.type = type;
this.name = name;
@@ -45,7 +73,9 @@ export class IndexPatternCreationConfig {
this.isBeta = isBeta;
}
- async getIndexPatternCreationOption(urlHandler) {
+ public async getIndexPatternCreationOption(
+ urlHandler: UrlHandler
+ ): Promise {
return {
text: indexPatternButtonText,
description: indexPatternButtonDescription,
@@ -56,39 +86,39 @@ export class IndexPatternCreationConfig {
};
}
- getIndexPatternType = () => {
+ public getIndexPatternType() {
return this.type;
}
- getIndexPatternName = () => {
+ public getIndexPatternName() {
return this.name;
}
- getIsBeta = () => {
+ public getIsBeta() {
return this.isBeta;
}
- getShowSystemIndices = () => {
+ public getShowSystemIndices() {
return this.showSystemIndices;
}
- getIndexTags() {
+ public getIndexTags() {
return [];
}
- checkIndicesForErrors = () => {
+ public checkIndicesForErrors() {
return undefined;
}
- getIndexPatternMappings = () => {
+ public getIndexPatternMappings() {
return {};
}
- renderPrompt = () => {
+ public renderPrompt() {
return null;
}
- getFetchForWildcardOptions = () => {
+ public getFetchForWildcardOptions() {
return {};
}
}
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/index.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/index.ts
new file mode 100644
index 0000000000000..84c4c28aa2260
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/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 { IndexPatternCreationConfig } from './config';
+export { IndexPatternCreationManager } from './manager';
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/manager.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/manager.ts
new file mode 100644
index 0000000000000..605ffdd6f2134
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/manager.ts
@@ -0,0 +1,61 @@
+/*
+ * 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 { HttpServiceBase } from '../../../../../../../../core/public';
+import { IndexPatternCreationConfig, UrlHandler, IndexPatternCreationOption } from './config';
+
+export class IndexPatternCreationManager {
+ private configs: IndexPatternCreationConfig[];
+
+ constructor(private readonly httpClient: HttpServiceBase) {
+ this.configs = [];
+ }
+
+ public add(Config: typeof IndexPatternCreationConfig) {
+ const config = new Config({ httpClient: this.httpClient });
+ if (this.configs.findIndex(c => c.key === config.key) !== -1) {
+ throw new Error(`${config.key} exists in IndexPatternCreationManager.`);
+ }
+ this.configs.push(config);
+ }
+
+ public getType(key: string | undefined): IndexPatternCreationConfig | null {
+ if (key) {
+ const index = this.configs.findIndex(config => config.key === key);
+ return this.configs[index] || null;
+ } else {
+ return this.getType('default');
+ }
+ }
+
+ public async getIndexPatternCreationOptions(urlHandler: UrlHandler) {
+ const options: IndexPatternCreationOption[] = [];
+ await Promise.all(
+ this.configs.map(async config => {
+ const option = config.getIndexPatternCreationOption
+ ? await config.getIndexPatternCreationOption(urlHandler)
+ : null;
+ if (option) {
+ options.push(option);
+ }
+ })
+ );
+ return options;
+ }
+}
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index.ts
new file mode 100644
index 0000000000000..2abe13eb0e292
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 * from './index_pattern_management_service';
+export { IndexPatternCreationConfig } from './creation';
+export { IndexPatternListConfig } from './list';
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index_pattern_management_service.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index_pattern_management_service.ts
new file mode 100644
index 0000000000000..b9e07564a324c
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index_pattern_management_service.ts
@@ -0,0 +1,53 @@
+/*
+ * 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 { HttpServiceBase } from '../../../../../../../core/public';
+import { IndexPatternCreationManager, IndexPatternCreationConfig } from './creation';
+import { IndexPatternListManager, IndexPatternListConfig } from './list';
+
+interface SetupDependencies {
+ httpClient: HttpServiceBase;
+}
+
+/**
+ * Index patterns management service
+ *
+ * @internal
+ */
+export class IndexPatternManagementService {
+ public setup({ httpClient }: SetupDependencies) {
+ const creation = new IndexPatternCreationManager(httpClient);
+ const list = new IndexPatternListManager();
+
+ creation.add(IndexPatternCreationConfig);
+ list.add(IndexPatternListConfig);
+
+ return {
+ creation,
+ list,
+ };
+ }
+
+ public stop() {
+ // nothing to do here yet.
+ }
+}
+
+/** @internal */
+export type IndexPatternManagementSetup = ReturnType;
diff --git a/src/plugins/kibana_utils/public/store/types.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/config.ts
similarity index 50%
rename from src/plugins/kibana_utils/public/store/types.ts
rename to src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/config.ts
index 952ee07f18baf..dd4d77a681171 100644
--- a/src/plugins/kibana_utils/public/store/types.ts
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/config.ts
@@ -17,26 +17,35 @@
* under the License.
*/
-import { Observable } from 'rxjs';
-import { Store as ReduxStore } from 'redux';
+import { i18n } from '@kbn/i18n';
+import { IIndexPattern, IFieldType } from 'src/plugins/data/public';
-export interface AppStore<
- State extends {},
- StateMutators extends Mutators> = {}
-> {
- redux: ReduxStore;
- get: () => State;
- set: (state: State) => void;
- state$: Observable;
- createMutators: >(pureMutators: M) => Mutators;
- mutators: StateMutators;
+export interface IndexPatternTag {
+ key: string;
+ name: string;
}
-export type PureMutator = (state: State) => (...args: any[]) => State;
-export type Mutator> = (...args: Parameters>) => void;
+export class IndexPatternListConfig {
+ public readonly key = 'default';
-export interface PureMutators {
- [name: string]: PureMutator;
-}
+ public getIndexPatternTags(indexPattern: IIndexPattern, isDefault: boolean): IndexPatternTag[] {
+ return isDefault
+ ? [
+ {
+ key: 'default',
+ name: i18n.translate('management.editIndexPattern.list.defaultIndexPatternListName', {
+ defaultMessage: 'Default',
+ }),
+ },
+ ]
+ : [];
+ }
+
+ public getFieldInfo(indexPattern: IIndexPattern, field: IFieldType): string[] {
+ return [];
+ }
-export type Mutators> = { [K in keyof M]: Mutator };
+ public areScriptedFieldsEnabled(indexPattern: IIndexPattern): boolean {
+ return true;
+ }
+}
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/index.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/index.ts
new file mode 100644
index 0000000000000..114226b3a4570
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/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 { IndexPatternListConfig } from './config';
+export { IndexPatternListManager } from './manager';
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/manager.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/manager.ts
new file mode 100644
index 0000000000000..73ca33ae914a9
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/manager.ts
@@ -0,0 +1,57 @@
+/*
+ * 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 { IIndexPattern, IFieldType } from 'src/plugins/data/public';
+import { IndexPatternListConfig, IndexPatternTag } from './config';
+
+export class IndexPatternListManager {
+ private configs: IndexPatternListConfig[];
+
+ constructor() {
+ this.configs = [];
+ }
+
+ public add(Config: typeof IndexPatternListConfig) {
+ const config = new Config();
+ if (this.configs.findIndex(c => c.key === config.key) !== -1) {
+ throw new Error(`${config.key} exists in IndexPatternListManager.`);
+ }
+ this.configs.push(config);
+ }
+
+ public getIndexPatternTags(indexPattern: IIndexPattern, isDefault: boolean) {
+ return this.configs.reduce((tags: IndexPatternTag[], config) => {
+ return config.getIndexPatternTags
+ ? tags.concat(config.getIndexPatternTags(indexPattern, isDefault))
+ : tags;
+ }, []);
+ }
+
+ public getFieldInfo(indexPattern: IIndexPattern, field: IFieldType): string[] {
+ return this.configs.reduce((info: string[], config) => {
+ return config.getFieldInfo ? info.concat(config.getFieldInfo(indexPattern, field)) : info;
+ }, []);
+ }
+
+ public areScriptedFieldsEnabled(indexPattern: IIndexPattern): boolean {
+ return this.configs.every(config => {
+ return config.areScriptedFieldsEnabled ? config.areScriptedFieldsEnabled(indexPattern) : true;
+ });
+ }
+}
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/index.ts b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/index.ts
new file mode 100644
index 0000000000000..bad3b3ac36ef7
--- /dev/null
+++ b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/index.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 * from './saved_objects_management_action_registry';
+export * from './saved_objects_management_action';
+export * from './saved_objects_management_service';
diff --git a/src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action.ts b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action.ts
similarity index 96%
rename from src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action.ts
rename to src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action.ts
index a09f842e36713..d83afb195a492 100644
--- a/src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action.ts
+++ b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { ReactNode } from '@elastic/eui/node_modules/@types/react';
+import { ReactNode } from 'react';
export interface SavedObjectsManagementRecordReference {
type: string;
diff --git a/src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action_registry.test.ts b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action_registry.test.ts
similarity index 100%
rename from src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action_registry.test.ts
rename to src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action_registry.test.ts
diff --git a/src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action_registry.ts b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action_registry.ts
similarity index 100%
rename from src/legacy/ui/public/management/saved_objects_management/saved_objects_management_action_registry.ts
rename to src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_action_registry.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_service.ts
similarity index 67%
rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts
rename to src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_service.ts
index 8445863b6dfc3..d5e90d12cccc9 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts
+++ b/src/legacy/core_plugins/management/public/np_ready/services/saved_objects_management/saved_objects_management_service.ts
@@ -16,10 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { SavedObjectsManagementActionRegistry } from './saved_objects_management_action_registry';
-import { DevToolsSettings } from '../../../../../services';
+export class SavedObjectsManagementService {
+ public setup() {
+ return {
+ registry: SavedObjectsManagementActionRegistry,
+ };
+ }
-export function applyCurrentSettings(editor: any, settings: DevToolsSettings) {
- editor.getSession().setUseWrapMode(settings.wrapMode);
- editor.$el.css('font-size', settings.fontSize + 'px');
+ public stop() {}
}
+
+/** @internal */
+export type SavedObjectsManagementServiceSetup = ReturnType;
diff --git a/src/legacy/core_plugins/state_session_storage_redirect/public/index.js b/src/legacy/core_plugins/state_session_storage_redirect/public/index.js
index 1aa7bce2af699..7fbf715ac3616 100644
--- a/src/legacy/core_plugins/state_session_storage_redirect/public/index.js
+++ b/src/legacy/core_plugins/state_session_storage_redirect/public/index.js
@@ -18,7 +18,7 @@
*/
import chrome from 'ui/chrome';
-import { hashUrl } from 'ui/state_management/state_hashing';
+import { hashUrl } from '../../../../plugins/kibana_utils/public';
import uiRoutes from 'ui/routes';
import { fatalError } from 'ui/notify';
diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts
index 5ae58204a8cf3..a2f98b8c64e53 100644
--- a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts
@@ -39,7 +39,7 @@ import { setup as visualizationsSetup } from '../../visualizations/public/np_rea
// eslint-disable-next-line
import { stubFields } from '../../../../plugins/data/public/stubs';
// eslint-disable-next-line
-import { setFieldFormats } from '../../../../plugins/data/public/index_patterns/services';
+import { setFieldFormats } from '../../../../plugins/data/public/services';
interface TableVisScope extends IScope {
[key: string]: any;
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/_mixins.scss b/src/legacy/core_plugins/vis_type_timeseries/public/_mixins.scss
index aefebe8117bbf..8d3aea2a3ae54 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/_mixins.scss
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/_mixins.scss
@@ -1,6 +1,3 @@
-@import 'node_modules/@elastic/eui/src/components/form/variables';
-@import 'node_modules/@elastic/eui/src/components/form/mixins';
-
@mixin tvbEditorRepeatingRow {
background-color: $euiColorLightestShade;
padding: $euiSizeS;
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/_annotations_editor.scss b/src/legacy/core_plugins/vis_type_timeseries/public/components/_annotations_editor.scss
index 3372367be273d..99e024c9c5193 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/_annotations_editor.scss
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/_annotations_editor.scss
@@ -1,11 +1,9 @@
-@import 'node_modules/@elastic/eui/src/components/panel/mixins';
-
.tvbAnnotationsEditor__container {
padding: $euiSize;
background-color: $euiColorLightestShade;
}
-@include euiPanel('tvbAnnotationsEditor');
+@include euiPanel('.tvbAnnotationsEditor');
.tvbAnnotationsEditor {
margin-bottom: $euiSize;
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/_series_editor.scss b/src/legacy/core_plugins/vis_type_timeseries/public/components/_series_editor.scss
index 0cfe5fef010d3..82d1f4ea62676 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/_series_editor.scss
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/_series_editor.scss
@@ -1,10 +1,8 @@
-@import 'node_modules/@elastic/eui/src/components/panel/mixins';
-
.tvbSeriesEditor__container {
padding: $euiSize;
}
-@include euiPanel('tvbSeriesEditor');
+@include euiPanel('.tvbSeriesEditor');
.tvbSeriesEditor {
margin-bottom: $euiSize;
diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js b/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js
index 7aa60bb0cc469..1a5c4713ef7e5 100644
--- a/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js
+++ b/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js
@@ -22,7 +22,6 @@ import { toastNotifications } from 'ui/notify';
import { VegaView } from './vega_view/vega_view';
import { VegaMapView } from './vega_view/vega_map_view';
import { timefilter } from 'ui/timefilter';
-import { start as data } from '../../../core_plugins/data/public/legacy';
import { npStart } from 'ui/new_platform';
import { findIndexPatternByTitle } from '../../data/public/index_patterns';
@@ -50,7 +49,7 @@ export const createVegaVisualization = ({ serviceSettings }) => class VegaVisual
}));
}
} else {
- idxObj = await data.indexPatterns.indexPatterns.getDefault();
+ idxObj = await npStart.plugins.data.indexPatterns.getDefault();
if (!idxObj) {
throw new Error(i18n.translate('visTypeVega.visualization.unableToFindDefaultIndexErrorMessage', {
defaultMessage: 'Unable to find default index',
diff --git a/src/legacy/core_plugins/visualizations/public/expressions/visualization_function.ts b/src/legacy/core_plugins/visualizations/public/expressions/visualization_function.ts
index 7076cdd8e23e3..ddf1b11945422 100644
--- a/src/legacy/core_plugins/visualizations/public/expressions/visualization_function.ts
+++ b/src/legacy/core_plugins/visualizations/public/expressions/visualization_function.ts
@@ -24,7 +24,7 @@ import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
import { PersistedState } from 'ui/persisted_state';
import { VisResponseValue } from 'src/plugins/visualizations/public';
import { ExpressionFunction, Render } from 'src/plugins/expressions/public';
-import { start as data } from '../../../data/public/legacy';
+import { npStart } from 'ui/new_platform';
import { start as visualizations } from '../np_ready/public/legacy';
interface Arguments {
@@ -92,7 +92,7 @@ export const visualization = (): ExpressionFunctionVisualization => ({
async fn(context, args, handlers) {
const $injector = await chrome.dangerouslyGetActiveInjector();
const Private = $injector.get('Private') as any;
- const { indexPatterns } = data.indexPatterns;
+ const indexPatterns = npStart.plugins.data.indexPatterns;
const queryFilter = Private(FilterBarQueryFilterProvider);
const visConfigParams = args.visConfig ? JSON.parse(args.visConfig) : {};
diff --git a/src/legacy/server/config/schema.js b/src/legacy/server/config/schema.js
index 24fe4e1a4d986..a19a39da0f6dd 100644
--- a/src/legacy/server/config/schema.js
+++ b/src/legacy/server/config/schema.js
@@ -135,7 +135,14 @@ export default () => Joi.object({
then: Joi.default(!process.stdout.isTTY),
otherwise: Joi.default(true)
}),
- timezone: Joi.string()
+ timezone: Joi.string(),
+ rotate: Joi.object().keys({
+ enabled: Joi.boolean().default(false),
+ everyBytes: Joi.number().greater(1024).default(10485760),
+ keepFiles: Joi.number().greater(2).less(1024).default(7),
+ pollingInterval: Joi.number().greater(5000).less(3600000).default(10000),
+ usePolling: Joi.boolean().default(false)
+ }).default()
}).default(),
ops: Joi.object({
diff --git a/src/legacy/server/logging/index.js b/src/legacy/server/logging/index.js
index 6e07757abf7bc..defbcd3331df4 100644
--- a/src/legacy/server/logging/index.js
+++ b/src/legacy/server/logging/index.js
@@ -20,6 +20,7 @@
import good from '@elastic/good';
import loggingConfiguration from './configuration';
import { logWithMetadata } from './log_with_metadata';
+import { setupLoggingRotate } from './rotate';
export async function setupLogging(server, config) {
return await server.register({
@@ -30,5 +31,7 @@ export async function setupLogging(server, config) {
export async function loggingMixin(kbnServer, server, config) {
logWithMetadata.decorateServer(server);
- return await setupLogging(server, config);
+
+ await setupLogging(server, config);
+ await setupLoggingRotate(server, config);
}
diff --git a/src/legacy/server/logging/rotate/index.ts b/src/legacy/server/logging/rotate/index.ts
new file mode 100644
index 0000000000000..646c89efe8e20
--- /dev/null
+++ b/src/legacy/server/logging/rotate/index.ts
@@ -0,0 +1,59 @@
+/*
+ * 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 { isMaster, isWorker } from 'cluster';
+import { Server } from 'hapi';
+import { LogRotator } from './log_rotator';
+import { KibanaConfig } from '../../kbn_server';
+
+let logRotator: LogRotator;
+
+export async function setupLoggingRotate(server: Server, config: KibanaConfig) {
+ // If log rotate is not enabled we skip
+ if (!config.get('logging.rotate.enabled')) {
+ return;
+ }
+
+ // We just want to start the logging rotate service once
+ // and we choose to use the master (prod) or the worker server (dev)
+ if (!isMaster && isWorker && process.env.kbnWorkerType !== 'server') {
+ return;
+ }
+
+ // We don't want to run logging rotate server if
+ // we are not logging to a file
+ if (config.get('logging.dest') === 'stdout') {
+ server.log(
+ ['warning', 'logging:rotate'],
+ 'Log rotation is enabled but logging.dest is configured for stdout. Set logging.dest to a file for this setting to take effect.'
+ );
+ return;
+ }
+
+ // Enable Logging Rotate Service
+ // We need the master process and it can
+ // try to setupLoggingRotate more than once,
+ // so we'll need to assure it only loads once.
+ if (!logRotator) {
+ logRotator = new LogRotator(config, server);
+ await logRotator.start();
+ }
+
+ return logRotator;
+}
diff --git a/src/legacy/server/logging/rotate/log_rotator.test.ts b/src/legacy/server/logging/rotate/log_rotator.test.ts
new file mode 100644
index 0000000000000..c2100546364d4
--- /dev/null
+++ b/src/legacy/server/logging/rotate/log_rotator.test.ts
@@ -0,0 +1,265 @@
+/*
+ * 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 del from 'del';
+import fs, { existsSync, mkdirSync, statSync, writeFileSync } from 'fs';
+import { LogRotator } from './log_rotator';
+import { tmpdir } from 'os';
+import { dirname, join } from 'path';
+
+const mockOn = jest.fn();
+jest.mock('chokidar', () => ({
+ watch: jest.fn(() => ({
+ on: mockOn,
+ close: jest.fn(),
+ })),
+}));
+
+jest.mock('lodash', () => ({
+ ...require.requireActual('lodash'),
+ throttle: (fn: any) => fn,
+}));
+
+const tempDir = join(tmpdir(), 'kbn_log_rotator_test');
+const testFilePath = join(tempDir, 'log_rotator_test_log_file.log');
+
+const createLogRotatorConfig: any = (logFilePath: string) => {
+ return new Map([
+ ['logging.dest', logFilePath],
+ ['logging.rotate.everyBytes', 2],
+ ['logging.rotate.keepFiles', 2],
+ ['logging.rotate.usePolling', false],
+ ['logging.rotate.pollingInterval', 10000],
+ ] as any);
+};
+
+const mockServer: any = {
+ log: jest.fn(),
+};
+
+const writeBytesToFile = (filePath: string, numberOfBytes: number) => {
+ writeFileSync(filePath, 'a'.repeat(numberOfBytes), { flag: 'a' });
+};
+
+describe('LogRotator', () => {
+ beforeEach(() => {
+ mkdirSync(tempDir, { recursive: true });
+ writeFileSync(testFilePath, '');
+ });
+
+ afterEach(() => {
+ del.sync(dirname(testFilePath), { force: true });
+ mockOn.mockClear();
+ });
+
+ it('rotates log file when bigger than set limit on start', async () => {
+ writeBytesToFile(testFilePath, 3);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+
+ await logRotator.stop();
+ const testLogFileDir = dirname(testFilePath);
+
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+ });
+
+ it('rotates log file when equal than set limit over time', async () => {
+ writeBytesToFile(testFilePath, 1);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+
+ const testLogFileDir = dirname(testFilePath);
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeFalsy();
+
+ writeBytesToFile(testFilePath, 1);
+
+ // ['change', [asyncFunction]]
+ const onChangeCb = mockOn.mock.calls[0][1];
+ await onChangeCb(testLogFileDir, { size: 2 });
+
+ await logRotator.stop();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+ });
+
+ it('rotates log file when file size is bigger than limit', async () => {
+ writeBytesToFile(testFilePath, 1);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+
+ const testLogFileDir = dirname(testFilePath);
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeFalsy();
+
+ writeBytesToFile(testFilePath, 2);
+
+ // ['change', [asyncFunction]]
+ const onChangeCb = mockOn.mock.calls[0][1];
+ await onChangeCb(testLogFileDir, { size: 3 });
+
+ await logRotator.stop();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+ });
+
+ it('rotates log file service correctly keeps number of files', async () => {
+ writeBytesToFile(testFilePath, 3);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+
+ const testLogFileDir = dirname(testFilePath);
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+
+ writeBytesToFile(testFilePath, 2);
+
+ // ['change', [asyncFunction]]
+ const onChangeCb = mockOn.mock.calls[0][1];
+ await onChangeCb(testLogFileDir, { size: 2 });
+
+ writeBytesToFile(testFilePath, 5);
+ await onChangeCb(testLogFileDir, { size: 5 });
+
+ await logRotator.stop();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.1'))).toBeTruthy();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.2'))).toBeFalsy();
+ expect(statSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0')).size).toBe(5);
+ });
+
+ it('rotates log file service correctly keeps number of files even when number setting changes', async () => {
+ writeBytesToFile(testFilePath, 3);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+
+ const testLogFileDir = dirname(testFilePath);
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+
+ writeBytesToFile(testFilePath, 2);
+
+ // ['change', [asyncFunction]]
+ const onChangeCb = mockOn.mock.calls[0][1];
+ await onChangeCb(testLogFileDir, { size: 2 });
+
+ writeBytesToFile(testFilePath, 5);
+ await onChangeCb(testLogFileDir, { size: 5 });
+
+ await logRotator.stop();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.1'))).toBeTruthy();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.2'))).toBeFalsy();
+ expect(statSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0')).size).toBe(5);
+
+ logRotator.keepFiles = 1;
+ await logRotator.start();
+
+ writeBytesToFile(testFilePath, 5);
+ await onChangeCb(testLogFileDir, { size: 5 });
+
+ await logRotator.stop();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0'))).toBeTruthy();
+ expect(existsSync(join(testLogFileDir, 'log_rotator_test_log_file.log.1'))).toBeFalsy();
+ expect(statSync(join(testLogFileDir, 'log_rotator_test_log_file.log.0')).size).toBe(5);
+ });
+
+ it('rotates log file service correctly detects usePolling when it should be false', async () => {
+ writeBytesToFile(testFilePath, 1);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+ expect(logRotator.usePolling).toBe(false);
+
+ const usePolling = await logRotator._shouldUsePolling();
+ expect(usePolling).toBe(false);
+
+ await logRotator.stop();
+ });
+
+ it('rotates log file service correctly detects usePolling when it should be true', async () => {
+ writeBytesToFile(testFilePath, 1);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+
+ jest.spyOn(fs, 'watch').mockImplementation(
+ () =>
+ ({
+ on: jest.fn((eventType, cb) => {
+ if (eventType === 'error') {
+ cb();
+ }
+ }),
+ close: jest.fn(),
+ } as any)
+ );
+
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+ expect(logRotator.usePolling).toBe(true);
+
+ await logRotator.stop();
+ });
+
+ it('rotates log file service correctly fallback to usePolling true after defined timeout', async () => {
+ jest.useFakeTimers();
+ writeBytesToFile(testFilePath, 1);
+
+ const logRotator = new LogRotator(createLogRotatorConfig(testFilePath), mockServer);
+ jest.spyOn(logRotator, '_sendReloadLogConfigSignal').mockImplementation(() => {});
+ jest.spyOn(fs, 'watch').mockImplementation(
+ () =>
+ ({
+ on: jest.fn((ev: string) => {
+ if (ev === 'error') {
+ jest.runTimersToTime(15000);
+ }
+ }),
+ close: jest.fn(),
+ } as any)
+ );
+
+ await logRotator.start();
+
+ expect(logRotator.running).toBe(true);
+ expect(logRotator.usePolling).toBe(true);
+
+ await logRotator.stop();
+ jest.useRealTimers();
+ });
+});
diff --git a/src/legacy/server/logging/rotate/log_rotator.ts b/src/legacy/server/logging/rotate/log_rotator.ts
new file mode 100644
index 0000000000000..3662910ca5a7b
--- /dev/null
+++ b/src/legacy/server/logging/rotate/log_rotator.ts
@@ -0,0 +1,359 @@
+/*
+ * 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 chokidar from 'chokidar';
+import { isMaster } from 'cluster';
+import fs from 'fs';
+import { Server } from 'hapi';
+import { throttle } from 'lodash';
+import { tmpdir } from 'os';
+import { basename, dirname, join, sep } from 'path';
+import { Observable } from 'rxjs';
+import { first } from 'rxjs/operators';
+import { promisify } from 'util';
+import { KibanaConfig } from '../../kbn_server';
+
+const mkdirAsync = promisify(fs.mkdir);
+const readdirAsync = promisify(fs.readdir);
+const renameAsync = promisify(fs.rename);
+const statAsync = promisify(fs.stat);
+const unlinkAsync = promisify(fs.unlink);
+const writeFileAsync = promisify(fs.writeFile);
+
+export class LogRotator {
+ private readonly config: KibanaConfig;
+ private readonly log: Server['log'];
+ public logFilePath: string;
+ public everyBytes: number;
+ public keepFiles: number;
+ public running: boolean;
+ private logFileSize: number;
+ public isRotating: boolean;
+ public throttledRotate: () => void;
+ public stalker: chokidar.FSWatcher | null;
+ public usePolling: boolean;
+ public pollingInterval: number;
+ private stalkerUsePollingPolicyTestTimeout: NodeJS.Timeout | null;
+
+ constructor(config: KibanaConfig, server: Server) {
+ this.config = config;
+ this.log = server.log.bind(server);
+ this.logFilePath = config.get('logging.dest');
+ this.everyBytes = config.get('logging.rotate.everyBytes');
+ this.keepFiles = config.get('logging.rotate.keepFiles');
+ this.running = false;
+ this.logFileSize = 0;
+ this.isRotating = false;
+ this.throttledRotate = throttle(async () => await this._rotate(), 5000);
+ this.stalker = null;
+ this.usePolling = config.get('logging.rotate.usePolling');
+ this.pollingInterval = config.get('logging.rotate.pollingInterval');
+ this.stalkerUsePollingPolicyTestTimeout = null;
+ }
+
+ async start() {
+ if (this.running) {
+ return;
+ }
+
+ this.running = true;
+
+ // create exit listener for cleanup purposes
+ this._createExitListener();
+
+ // call rotate on startup
+ await this._callRotateOnStartup();
+
+ // init log file size monitor
+ await this._startLogFileSizeMonitor();
+ }
+
+ stop = () => {
+ if (!this.running) {
+ return;
+ }
+
+ // cleanup exit listener
+ this._deleteExitListener();
+
+ // stop log file size monitor
+ this._stopLogFileSizeMonitor();
+
+ this.running = false;
+ };
+
+ async _shouldUsePolling() {
+ try {
+ // Setup a test file in order to try the fs env
+ // and understand if we need to usePolling or not
+ const tempFileDir = tmpdir();
+ const tempFile = join(tempFileDir, 'kbn_log_rotation_use_polling_test_file.log');
+
+ await mkdirAsync(tempFileDir, { recursive: true });
+ await writeFileAsync(tempFile, '');
+
+ // setup fs.watch for the temp test file
+ const testWatcher = fs.watch(tempFile, { persistent: false });
+
+ // await writeFileAsync(tempFile, 'test');
+
+ const usePollingTest$ = new Observable(observer => {
+ // observable complete function
+ const completeFn = (completeStatus: boolean) => {
+ if (this.stalkerUsePollingPolicyTestTimeout) {
+ clearTimeout(this.stalkerUsePollingPolicyTestTimeout);
+ }
+ testWatcher.close();
+
+ observer.next(completeStatus);
+ observer.complete();
+ };
+
+ // setup conditions that would fire the observable
+ this.stalkerUsePollingPolicyTestTimeout = setTimeout(() => completeFn(true), 15000);
+ testWatcher.on('change', () => completeFn(false));
+ testWatcher.on('error', () => completeFn(true));
+
+ // fire test watcher events
+ setTimeout(() => {
+ fs.writeFileSync(tempFile, 'test');
+ }, 0);
+ });
+
+ // wait for the first observable result and consider it as the result
+ // for our use polling test
+ const usePollingTestResult = await usePollingTest$.pipe(first()).toPromise();
+
+ // delete the temp file used for the test
+ await unlinkAsync(tempFile);
+
+ return usePollingTestResult;
+ } catch {
+ return true;
+ }
+ }
+
+ async _startLogFileSizeMonitor() {
+ this.usePolling = await this._shouldUsePolling();
+
+ if (this.usePolling && this.usePolling !== this.config.get('logging.rotate.usePolling')) {
+ this.log(
+ ['warning', 'logging:rotate'],
+ 'The current environment does not support `fs.watch`. Falling back to polling using `fs.watchFile`'
+ );
+ }
+
+ this.stalker = chokidar.watch(this.logFilePath, {
+ ignoreInitial: true,
+ awaitWriteFinish: false,
+ useFsEvents: false,
+ usePolling: this.usePolling,
+ interval: this.pollingInterval,
+ binaryInterval: this.pollingInterval,
+ alwaysStat: true,
+ atomic: false,
+ });
+ this.stalker.on('change', this._logFileSizeMonitorHandler);
+ }
+
+ _logFileSizeMonitorHandler = async (filename: string, stats: fs.Stats) => {
+ if (!filename || !stats) {
+ return;
+ }
+
+ this.logFileSize = stats.size || 0;
+ await this.throttledRotate();
+ };
+
+ _stopLogFileSizeMonitor() {
+ if (!this.stalker) {
+ return;
+ }
+
+ this.stalker.close();
+
+ if (this.stalkerUsePollingPolicyTestTimeout) {
+ clearTimeout(this.stalkerUsePollingPolicyTestTimeout);
+ }
+ }
+
+ _createExitListener() {
+ process.on('exit', this.stop);
+ }
+
+ _deleteExitListener() {
+ process.removeListener('exit', this.stop);
+ }
+
+ async _getLogFileSizeAndCreateIfNeeded() {
+ try {
+ const logFileStats = await statAsync(this.logFilePath);
+ return logFileStats.size;
+ } catch {
+ // touch the file to make the watcher being able to register
+ // change events
+ await writeFileAsync(this.logFilePath, '');
+ return 0;
+ }
+ }
+
+ async _callRotateOnStartup() {
+ this.logFileSize = await this._getLogFileSizeAndCreateIfNeeded();
+ await this._rotate();
+ }
+
+ _shouldRotate() {
+ // should rotate evaluation
+ // 1. should rotate if current log size exceeds
+ // the defined one on everyBytes
+ // 2. should not rotate if is already rotating or if any
+ // of the conditions on 1. do not apply
+ if (this.isRotating) {
+ return false;
+ }
+
+ return this.logFileSize >= this.everyBytes;
+ }
+
+ async _rotate() {
+ if (!this._shouldRotate()) {
+ return;
+ }
+
+ await this._rotateNow();
+ }
+
+ async _rotateNow() {
+ // rotate process
+ // 1. get rotated files metadata (list of log rotated files present on the log folder, numerical sorted)
+ // 2. delete last file
+ // 3. rename all files to the correct index +1
+ // 4. rename + compress current log into 1
+ // 5. send SIGHUP to reload log config
+
+ // rotate process is starting
+ this.isRotating = true;
+
+ // get rotated files metadata
+ const foundRotatedFiles = await this._readRotatedFilesMetadata();
+
+ // delete number of rotated files exceeding the keepFiles limit setting
+ const rotatedFiles: string[] = await this._deleteFoundRotatedFilesAboveKeepFilesLimit(
+ foundRotatedFiles
+ );
+
+ // delete last file
+ await this._deleteLastRotatedFile(rotatedFiles);
+
+ // rename all files to correct index + 1
+ // and normalize numbering if by some reason
+ // (for example log file deletion) that numbering
+ // was interrupted
+ await this._renameRotatedFilesByOne(rotatedFiles);
+
+ // rename current log into 0
+ await this._rotateCurrentLogFile();
+
+ // send SIGHUP to reload log configuration
+ this._sendReloadLogConfigSignal();
+
+ // Reset log file size
+ this.logFileSize = 0;
+
+ // rotate process is finished
+ this.isRotating = false;
+ }
+
+ async _readRotatedFilesMetadata() {
+ const logFileBaseName = basename(this.logFilePath);
+ const logFilesFolder = dirname(this.logFilePath);
+ const foundLogFiles: string[] = await readdirAsync(logFilesFolder);
+
+ return (
+ foundLogFiles
+ .filter(file => new RegExp(`${logFileBaseName}\\.\\d`).test(file))
+ // we use .slice(-1) here in order to retrieve the last number match in the read filenames
+ .sort((a, b) => Number(a.match(/(\d+)/g)!.slice(-1)) - Number(b.match(/(\d+)/g)!.slice(-1)))
+ .map(filename => `${logFilesFolder}${sep}${filename}`)
+ );
+ }
+
+ async _deleteFoundRotatedFilesAboveKeepFilesLimit(foundRotatedFiles: string[]) {
+ if (foundRotatedFiles.length <= this.keepFiles) {
+ return foundRotatedFiles;
+ }
+
+ const finalRotatedFiles = foundRotatedFiles.slice(0, this.keepFiles);
+ const rotatedFilesToDelete = foundRotatedFiles.slice(
+ finalRotatedFiles.length,
+ foundRotatedFiles.length
+ );
+
+ await Promise.all(
+ rotatedFilesToDelete.map((rotatedFilePath: string) => unlinkAsync(rotatedFilePath))
+ );
+
+ return finalRotatedFiles;
+ }
+
+ async _deleteLastRotatedFile(rotatedFiles: string[]) {
+ if (rotatedFiles.length < this.keepFiles) {
+ return;
+ }
+
+ const lastFilePath: string = rotatedFiles.pop() as string;
+ await unlinkAsync(lastFilePath);
+ }
+
+ async _renameRotatedFilesByOne(rotatedFiles: string[]) {
+ const logFileBaseName = basename(this.logFilePath);
+ const logFilesFolder = dirname(this.logFilePath);
+
+ for (let i = rotatedFiles.length - 1; i >= 0; i--) {
+ const oldFilePath = rotatedFiles[i];
+ const newFilePath = `${logFilesFolder}${sep}${logFileBaseName}.${i + 1}`;
+ await renameAsync(oldFilePath, newFilePath);
+ }
+ }
+
+ async _rotateCurrentLogFile() {
+ const newFilePath = `${this.logFilePath}.0`;
+ await renameAsync(this.logFilePath, newFilePath);
+ }
+
+ _sendReloadLogConfigSignal() {
+ if (isMaster) {
+ (process as NodeJS.EventEmitter).emit('SIGHUP');
+ return;
+ }
+
+ // Send a special message to the cluster manager
+ // so it can forward it correctly
+ // It will only run when we are under cluster mode (not under a production environment)
+ if (!process.send) {
+ this.log(
+ ['error', 'logging:rotate'],
+ 'For some unknown reason process.send is not defined, the rotation was not successful'
+ );
+ return;
+ }
+
+ process.send(['RELOAD_LOGGING_CONFIG_FROM_SERVER_WORKER']);
+ }
+}
diff --git a/src/legacy/server/sass/build.test.js b/src/legacy/server/sass/build.test.js
index 810b7cb44b917..bde552e9df00f 100644
--- a/src/legacy/server/sass/build.test.js
+++ b/src/legacy/server/sass/build.test.js
@@ -47,14 +47,35 @@ it('builds light themed SASS', async () => {
expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2'))
.toMatchInlineSnapshot(`
-"foo bar {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- background: #e6f0f8 url(./images/img.png) url(ui/assets/favicons/favicon.ico); }
-/*# sourceMappingURL=... */"
-`);
+ "/* 1 */
+ /* 1 */
+ /**
+ * 1. Extend beta badges to at least 40% of the container's width
+ * 2. Fix for IE to ensure badges are visible outside of a tag
+ */
+ /**
+ * 1. Apply margin to all but last item in the flex.
+ * 2. Margin gets flipped because of the row-reverse.
+ */
+ /**
+ * 3. Must supply both values to background-size or some browsers apply the single value to both directions
+ */
+ /**
+ * 4. Override invalid state with focus state.
+ */
+ /**
+ * Mixin for use in:
+ * - EuiCard
+ * - EuiPageContent
+ */
+ foo bar {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ background: #e6f0f8 url(./images/img.png) url(ui/assets/favicons/favicon.ico); }
+ /*# sourceMappingURL=... */"
+ `);
});
it('builds dark themed SASS', async () => {
@@ -72,14 +93,35 @@ it('builds dark themed SASS', async () => {
expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2'))
.toMatchInlineSnapshot(`
-"foo bar {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- background: #232635 url(./images/img.png) url(ui/assets/favicons/favicon.ico); }
-/*# sourceMappingURL=... */"
-`);
+ "/* 1 */
+ /* 1 */
+ /**
+ * 1. Extend beta badges to at least 40% of the container's width
+ * 2. Fix for IE to ensure badges are visible outside of a tag
+ */
+ /**
+ * 1. Apply margin to all but last item in the flex.
+ * 2. Margin gets flipped because of the row-reverse.
+ */
+ /**
+ * 3. Must supply both values to background-size or some browsers apply the single value to both directions
+ */
+ /**
+ * 4. Override invalid state with focus state.
+ */
+ /**
+ * Mixin for use in:
+ * - EuiCard
+ * - EuiPageContent
+ */
+ foo bar {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ background: #232635 url(./images/img.png) url(ui/assets/favicons/favicon.ico); }
+ /*# sourceMappingURL=... */"
+ `);
});
it('rewrites url imports', async () => {
@@ -99,16 +141,38 @@ it('rewrites url imports', async () => {
},
}).build();
+ /* eslint-disable max-len */
expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2'))
.toMatchInlineSnapshot(`
-"foo bar {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- background: #232635 url(__REPLACE_WITH_PUBLIC_PATH__foo/bar/images/img.png) url(__REPLACE_WITH_PUBLIC_PATH__ui/favicons/favicon.ico); }
-/*# sourceMappingURL=... */"
-`);
+ "/* 1 */
+ /* 1 */
+ /**
+ * 1. Extend beta badges to at least 40% of the container's width
+ * 2. Fix for IE to ensure badges are visible outside of a tag
+ */
+ /**
+ * 1. Apply margin to all but last item in the flex.
+ * 2. Margin gets flipped because of the row-reverse.
+ */
+ /**
+ * 3. Must supply both values to background-size or some browsers apply the single value to both directions
+ */
+ /**
+ * 4. Override invalid state with focus state.
+ */
+ /**
+ * Mixin for use in:
+ * - EuiCard
+ * - EuiPageContent
+ */
+ foo bar {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ background: #232635 url(__REPLACE_WITH_PUBLIC_PATH__foo/bar/images/img.png) url(__REPLACE_WITH_PUBLIC_PATH__ui/favicons/favicon.ico); }
+ /*# sourceMappingURL=... */"
+ `);
expect(
Buffer.compare(
@@ -118,9 +182,9 @@ it('rewrites url imports', async () => {
).toBe(0);
expect(await globby('**/*', { cwd: TMP })).toMatchInlineSnapshot(`
-Array [
- "style.css",
- "images/img.png",
-]
-`);
+ Array [
+ "style.css",
+ "images/img.png",
+ ]
+ `);
});
diff --git a/src/legacy/ui/public/agg_types/param_types/field.ts b/src/legacy/ui/public/agg_types/param_types/field.ts
index ab60f5553f79b..4fda86bd1379f 100644
--- a/src/legacy/ui/public/agg_types/param_types/field.ts
+++ b/src/legacy/ui/public/agg_types/param_types/field.ts
@@ -25,7 +25,7 @@ import { FieldParamEditor } from '../../vis/editors/default/controls/field';
import { BaseParamType } from './base';
import { toastNotifications } from '../../notify';
import { propFilter } from '../filter';
-import { Field, FieldListInterface } from '../../index_patterns';
+import { Field, IFieldList } from '../../index_patterns';
const filterByType = propFilter('type');
@@ -111,7 +111,7 @@ export class FieldParamType extends BaseParamType {
/**
* filter the fields to the available ones
*/
- getAvailableFields = (fields: FieldListInterface) => {
+ getAvailableFields = (fields: IFieldList) => {
const filteredFields = fields.filter((field: Field) => {
const { onlyAggregatable, scriptable, filterFieldTypes } = this;
diff --git a/src/legacy/ui/public/chrome/api/sub_url_hooks.js b/src/legacy/ui/public/chrome/api/sub_url_hooks.js
index e38a1f4b19e56..3ff262f546e3c 100644
--- a/src/legacy/ui/public/chrome/api/sub_url_hooks.js
+++ b/src/legacy/ui/public/chrome/api/sub_url_hooks.js
@@ -19,9 +19,8 @@
import url from 'url';
-import {
- unhashUrl,
-} from '../../state_management/state_hashing';
+import { unhashUrl } from '../../../../../plugins/kibana_utils/public';
+import { toastNotifications } from '../../notify/toasts';
export function registerSubUrlHooks(angularModule, internals) {
angularModule.run(($rootScope, Private, $location) => {
@@ -29,8 +28,14 @@ export function registerSubUrlHooks(angularModule, internals) {
function updateSubUrls() {
const urlWithHashes = window.location.href;
- const urlWithStates = unhashUrl(urlWithHashes);
- internals.trackPossibleSubUrl(urlWithStates);
+ let urlWithStates;
+ try {
+ urlWithStates = unhashUrl(urlWithHashes);
+ } catch (e) {
+ toastNotifications.addDanger(e.message);
+ }
+
+ internals.trackPossibleSubUrl(urlWithStates || urlWithHashes);
}
function onRouteChange($event) {
diff --git a/src/legacy/ui/public/index_patterns/__mocks__/index.ts b/src/legacy/ui/public/index_patterns/__mocks__/index.ts
index 6f3d39299f970..0cb1cf897b166 100644
--- a/src/legacy/ui/public/index_patterns/__mocks__/index.ts
+++ b/src/legacy/ui/public/index_patterns/__mocks__/index.ts
@@ -17,18 +17,9 @@
* under the License.
*/
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { dataPluginMock } from '../../../../../plugins/data/public/mocks';
import { indexPatterns as npIndexPatterns } from '../../../../../plugins/data/public';
-const dataSetup = dataPluginMock.createSetupContract();
-
-// mocks for stateful code
-export const { indexPatterns } = dataSetup.indexPatterns!;
-
export const flattenHitWrapper = npIndexPatterns.flattenHitWrapper;
-export const formatHitProvider = npIndexPatterns.formatHitProvider;
// static code
export { getFromSavedObject, getRoutes } from '../../../../core_plugins/data/public';
-export { FieldList } from '../../../../../plugins/data/public';
diff --git a/src/legacy/ui/public/index_patterns/index.ts b/src/legacy/ui/public/index_patterns/index.ts
index 237f3137bc9f4..47f6e697c54e9 100644
--- a/src/legacy/ui/public/index_patterns/index.ts
+++ b/src/legacy/ui/public/index_patterns/index.ts
@@ -27,23 +27,14 @@
import { indexPatterns } from '../../../../plugins/data/public';
// static code
-export { getFromSavedObject, getRoutes } from '../../../core_plugins/data/public';
-
export const INDEX_PATTERN_ILLEGAL_CHARACTERS = indexPatterns.ILLEGAL_CHARACTERS;
export const INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE = indexPatterns.ILLEGAL_CHARACTERS_VISIBLE;
export const ILLEGAL_CHARACTERS = indexPatterns.ILLEGAL_CHARACTERS_KEY;
export const CONTAINS_SPACES = indexPatterns.CONTAINS_SPACES_KEY;
export const validateIndexPattern = indexPatterns.validate;
export const flattenHitWrapper = indexPatterns.flattenHitWrapper;
-export const formatHitProvider = indexPatterns.formatHitProvider;
+export const getFromSavedObject = indexPatterns.getFromSavedObject;
+export const getRoutes = indexPatterns.getRoutes;
// types
-export {
- Field,
- FieldType,
- FieldListInterface,
- IndexPattern,
- IndexPatterns,
-} from '../../../core_plugins/data/public';
-
-export { FieldList } from '../../../../plugins/data/public';
+export { Field, FieldType, IFieldList, IndexPattern } from '../../../core_plugins/data/public';
diff --git a/src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx b/src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx
index 98e95865d7325..bb6b9f805b413 100644
--- a/src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx
+++ b/src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx
@@ -25,7 +25,7 @@ import { i18n } from '@kbn/i18n';
import { I18nProvider } from '@kbn/i18n/react';
import { EuiCallOut } from '@elastic/eui';
import { CoreStart } from 'kibana/public';
-import { DataStart } from '../../../core_plugins/data/public';
+import { DataPublicPluginStart } from 'src/plugins/data/public';
let bannerId: string;
let timeoutId: NodeJS.Timeout | undefined;
@@ -40,11 +40,11 @@ let timeoutId: NodeJS.Timeout | undefined;
*/
export async function ensureDefaultIndexPattern(
newPlatform: CoreStart,
- data: DataStart,
+ data: DataPublicPluginStart,
$rootScope: IRootScopeService,
kbnUrl: any
) {
- const patterns = await data.indexPatterns.indexPatterns.getIds();
+ const patterns = await data.indexPatterns.getIds();
let defaultId = newPlatform.uiSettings.get('defaultIndex');
let defined = !!defaultId;
const exists = contains(patterns, defaultId);
diff --git a/src/legacy/ui/public/management/index_pattern_creation/index.js b/src/legacy/ui/public/management/index_pattern_creation/index.js
deleted file mode 100644
index 0b677cbfd1f64..0000000000000
--- a/src/legacy/ui/public/management/index_pattern_creation/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import './register';
-export { IndexPatternCreationFactory } from './index_pattern_creation';
-export { IndexPatternCreationConfig } from './index_pattern_creation_config';
-export { indexPatternTypes, addIndexPatternType } from './index_pattern_types';
diff --git a/src/legacy/ui/public/management/index_pattern_creation/index_pattern_creation.js b/src/legacy/ui/public/management/index_pattern_creation/index_pattern_creation.js
deleted file mode 100644
index 12cecc956ab68..0000000000000
--- a/src/legacy/ui/public/management/index_pattern_creation/index_pattern_creation.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { indexPatternTypes } from './index_pattern_types';
-
-class IndexPatternCreation {
- constructor(httpClient, type) {
- this._allTypes = indexPatternTypes.map(Plugin => new Plugin({ httpClient }));
- this._setCurrentType(type);
- }
-
- _setCurrentType = (type) => {
- const index = type ? indexPatternTypes.findIndex(Plugin => Plugin.key === type) : -1;
- this._currentType = index > -1 && this._allTypes[index] ? this._allTypes[index] : null;
- }
-
- getType = () => {
- return this._currentType || null;
- }
-
- getIndexPatternCreationOptions = async (urlHandler) => {
- const options = [];
- await Promise.all(this._allTypes.map(async type => {
- const option = type.getIndexPatternCreationOption ? await type.getIndexPatternCreationOption(urlHandler) : null;
- if(option) {
- options.push(option);
- }
- }));
- return options;
- }
-}
-
-export const IndexPatternCreationFactory = (Private, $http) => {
- return (type = 'default') => {
- const indexPatternCreationProvider = new IndexPatternCreation($http, type);
- return indexPatternCreationProvider;
- };
-};
diff --git a/src/legacy/ui/public/management/index_pattern_list/index.js b/src/legacy/ui/public/management/index_pattern_list/index.js
deleted file mode 100644
index a77a3f1f61f2c..0000000000000
--- a/src/legacy/ui/public/management/index_pattern_list/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import './register';
-export { IndexPatternListFactory } from './index_pattern_list';
-export { IndexPatternListConfig } from './index_pattern_list_config';
-export { IndexPatternListConfigRegistry } from './index_pattern_list_config_registry';
diff --git a/src/legacy/ui/public/management/index_pattern_list/index_pattern_list.js b/src/legacy/ui/public/management/index_pattern_list/index_pattern_list.js
deleted file mode 100644
index 9ff82db27fefc..0000000000000
--- a/src/legacy/ui/public/management/index_pattern_list/index_pattern_list.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { IndexPatternListConfigRegistry } from './index_pattern_list_config_registry';
-
-class IndexPatternList {
- constructor(registry) {
- this._plugins = registry.inOrder.map(Plugin => new Plugin());
- }
-
- getIndexPatternTags = (indexPattern, isDefault) => {
- return this._plugins.reduce((tags, plugin) => {
- return plugin.getIndexPatternTags ? tags.concat(plugin.getIndexPatternTags(indexPattern, isDefault)) : tags;
- }, []);
- }
-
- getFieldInfo = (indexPattern, field) => {
- return this._plugins.reduce((info, plugin) => {
- return plugin.getFieldInfo ? info.concat(plugin.getFieldInfo(indexPattern, field)) : info;
- }, []);
- }
-
- areScriptedFieldsEnabled = (indexPattern) => {
- return this._plugins.every((plugin) => {
- return plugin.areScriptedFieldsEnabled ? plugin.areScriptedFieldsEnabled(indexPattern) : true;
- });
- }
-}
-
-export const IndexPatternListFactory = (Private) => {
- return function () {
- const indexPatternListRegistry = Private(IndexPatternListConfigRegistry);
- const indexPatternListProvider = new IndexPatternList(indexPatternListRegistry);
- return indexPatternListProvider;
- };
-};
diff --git a/src/legacy/ui/public/management/section.js b/src/legacy/ui/public/management/section.js
index d5e70c03d4259..b6952695cd910 100644
--- a/src/legacy/ui/public/management/section.js
+++ b/src/legacy/ui/public/management/section.js
@@ -42,7 +42,7 @@ export class ManagementSection {
this.id = id;
this.items = new IndexedArray({
index: ['id'],
- order: ['order']
+ order: ['order'],
});
this.visible = true;
this.disabled = false;
@@ -51,13 +51,14 @@ export class ManagementSection {
this.url = '';
assign(this, options);
-
}
get visibleItems() {
return this.items.inOrder.filter(item => {
const capabilityManagementSection = capabilities.get().management[this.id];
- const itemCapability = capabilityManagementSection ? capabilityManagementSection[item.id] : null;
+ const itemCapability = capabilityManagementSection
+ ? capabilityManagementSection[item.id]
+ : null;
return item.visible && itemCapability !== false;
});
@@ -95,10 +96,10 @@ export class ManagementSection {
}
/**
- * Deregisters a section
- *
- * @param {string} id
- */
+ * Deregisters a section
+ *
+ * @param {string} id
+ */
deregister(id) {
this.items.remove(item => item.id === id);
listeners.forEach(fn => fn(this.items));
diff --git a/src/legacy/ui/public/management/section.test.js b/src/legacy/ui/public/management/section.test.js
index a45fca426e2b4..e6363f2e164b4 100644
--- a/src/legacy/ui/public/management/section.test.js
+++ b/src/legacy/ui/public/management/section.test.js
@@ -24,10 +24,10 @@ jest.mock('ui/capabilities', () => ({
kibana: {
sampleFeature1: true,
sampleFeature2: false,
- }
- }
- })
- }
+ },
+ },
+ }),
+ },
}));
import { ManagementSection } from './section';
@@ -115,7 +115,9 @@ describe('ManagementSection', () => {
it('calls listener when item added', () => {
let listerCalled = false;
- const listenerFn = () => { listerCalled = true; };
+ const listenerFn = () => {
+ listerCalled = true;
+ };
section.addListener(listenerFn);
section.register('about');
@@ -131,12 +133,12 @@ describe('ManagementSection', () => {
section.register('about');
});
- it ('deregisters an existing section', () => {
+ it('deregisters an existing section', () => {
section.deregister('about');
expect(section.items).toHaveLength(0);
});
- it ('allows deregistering a section more than once', () => {
+ it('allows deregistering a section more than once', () => {
section.deregister('about');
section.deregister('about');
expect(section.items).toHaveLength(0);
@@ -144,7 +146,9 @@ describe('ManagementSection', () => {
it('calls listener when item added', () => {
let listerCalled = false;
- const listenerFn = () => { listerCalled = true; };
+ const listenerFn = () => {
+ listerCalled = true;
+ };
section.addListener(listenerFn);
section.deregister('about');
@@ -202,7 +206,9 @@ describe('ManagementSection', () => {
});
it('can be ordered', () => {
- const ids = section.items.inOrder.map((i) => { return i.id; });
+ const ids = section.items.inOrder.map(i => {
+ return i.id;
+ });
expect(ids).toEqual(['one', 'two', 'three']);
});
});
@@ -256,20 +262,26 @@ describe('ManagementSection', () => {
});
it('maintains the order', () => {
- const ids = section.visibleItems.map((i) => { return i.id; });
+ const ids = section.visibleItems.map(i => {
+ return i.id;
+ });
expect(ids).toEqual(['one', 'two', 'three']);
});
it('does not include hidden items', () => {
section.getSection('two').hide();
- const ids = section.visibleItems.map((i) => { return i.id; });
+ const ids = section.visibleItems.map(i => {
+ return i.id;
+ });
expect(ids).toEqual(['one', 'three']);
});
it('does not include visible items hidden via uiCapabilities', () => {
section.register('sampleFeature2', { order: 4, visible: true });
- const ids = section.visibleItems.map((i) => { return i.id; });
+ const ids = section.visibleItems.map(i => {
+ return i.id;
+ });
expect(ids).toEqual(['one', 'two', 'three']);
});
});
diff --git a/src/legacy/ui/public/management/sections_register.js b/src/legacy/ui/public/management/sections_register.js
index b25b381eef67b..a63fd390ea3ca 100644
--- a/src/legacy/ui/public/management/sections_register.js
+++ b/src/legacy/ui/public/management/sections_register.js
@@ -22,15 +22,15 @@ import { i18n } from '@kbn/i18n';
export const management = new ManagementSection('management', {
display: i18n.translate('common.ui.management.displayName', {
- defaultMessage: 'Management'
- })
+ defaultMessage: 'Management',
+ }),
});
management.register('data', {
display: i18n.translate('common.ui.management.connectDataDisplayName', {
- defaultMessage: 'Connect Data'
+ defaultMessage: 'Connect Data',
}),
- order: 0
+ order: 0,
});
management.register('elasticsearch', {
diff --git a/src/legacy/ui/public/state_management/__tests__/state.js b/src/legacy/ui/public/state_management/__tests__/state.js
index 6f6f74c9d2bec..475d7c44a5f5a 100644
--- a/src/legacy/ui/public/state_management/__tests__/state.js
+++ b/src/legacy/ui/public/state_management/__tests__/state.js
@@ -26,11 +26,11 @@ import { toastNotifications } from '../../notify';
import * as FatalErrorNS from '../../notify/fatal_error';
import { StateProvider } from '../state';
import {
+ unhashQuery,
createStateHash,
isStateHash,
- unhashQuery
-} from '../state_hashing';
-import { HashedItemStore } from '../../../../../plugins/kibana_utils/public';
+ HashedItemStore
+} from '../../../../../plugins/kibana_utils/public';
import { StubBrowserStorage } from 'test_utils/stub_browser_storage';
import { EventsProvider } from '../../events';
diff --git a/src/legacy/ui/public/state_management/state.js b/src/legacy/ui/public/state_management/state.js
index 359dfa5749611..27186b4249978 100644
--- a/src/legacy/ui/public/state_management/state.js
+++ b/src/legacy/ui/public/state_management/state.js
@@ -35,11 +35,7 @@ import { fatalError, toastNotifications } from '../notify';
import './config_provider';
import { createLegacyClass } from '../utils/legacy_class';
import { callEach } from '../utils/function';
-import { hashedItemStore } from '../../../../plugins/kibana_utils/public';
-import {
- createStateHash,
- isStateHash
-} from './state_hashing';
+import { hashedItemStore, isStateHash, createStateHash } from '../../../../plugins/kibana_utils/public';
export function StateProvider(Private, $rootScope, $location, stateManagementConfig, config, kbnUrl, $injector) {
const Events = Private(EventsProvider);
diff --git a/src/legacy/ui/public/styles/_legacy/_mixins.scss b/src/legacy/ui/public/styles/_legacy/_mixins.scss
index b063aa763838b..2834f60555070 100644
--- a/src/legacy/ui/public/styles/_legacy/_mixins.scss
+++ b/src/legacy/ui/public/styles/_legacy/_mixins.scss
@@ -3,8 +3,6 @@
// DO NOT CONTINUE TO USE THESE MIXINS
-@import '@elastic/eui/src/components/form/variables';
-
@mixin __legacyInputStyles__bad {
&:not([type='range']) {
appearance: none;
diff --git a/src/legacy/ui/public/styles/_legacy/components/_ui_select.scss b/src/legacy/ui/public/styles/_legacy/components/_ui_select.scss
index 50ec20f016194..691ec17b5b967 100644
--- a/src/legacy/ui/public/styles/_legacy/components/_ui_select.scss
+++ b/src/legacy/ui/public/styles/_legacy/components/_ui_select.scss
@@ -1,6 +1,3 @@
-@import '@elastic/eui/src/components/button/variables';
-@import '@elastic/eui/src/components/form/variables';
-
/*!
* ui-select
* http://github.com/angular-ui/ui-select
@@ -8,7 +5,6 @@
* License: MIT
*/
-
/* Style when highlighting a search. */
.ui-select-highlight {
font-weight: bold;
@@ -43,12 +39,12 @@
padding-left: 0;
}
-.select2-locked > .select2-search-choice-close{
- display:none;
+.select2-locked > .select2-search-choice-close {
+ display: none;
}
-.select-locked > .ui-select-match-close{
- display:none;
+.select-locked > .ui-select-match-close {
+ display: none;
}
body > .select2-container.open {
@@ -56,42 +52,42 @@ body > .select2-container.open {
}
/* Handle up direction Select2 */
-.ui-select-container[theme="select2"].direction-up .ui-select-match,
+.ui-select-container[theme='select2'].direction-up .ui-select-match,
.ui-select-container.select2.direction-up .ui-select-match {
- border-radius: 4px; /* FIXME hardcoded value :-/ */
- border-top-left-radius: 0;
- border-top-right-radius: 0;
+ border-radius: 4px; /* FIXME hardcoded value :-/ */
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
}
-.ui-select-container[theme="select2"].direction-up .ui-select-dropdown,
+.ui-select-container[theme='select2'].direction-up .ui-select-dropdown,
.ui-select-container.select2.direction-up .ui-select-dropdown {
- border-radius: 4px; /* FIXME hardcoded value :-/ */
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
+ border-radius: 4px; /* FIXME hardcoded value :-/ */
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
- border-top-width: 1px; /* FIXME hardcoded value :-/ */
- border-top-style: solid;
+ border-top-width: 1px; /* FIXME hardcoded value :-/ */
+ border-top-style: solid;
- box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
+ box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
- margin-top: -4px; /* FIXME hardcoded value :-/ */
+ margin-top: -4px; /* FIXME hardcoded value :-/ */
}
-.ui-select-container[theme="select2"].direction-up .ui-select-dropdown .select2-search,
+.ui-select-container[theme='select2'].direction-up .ui-select-dropdown .select2-search,
.ui-select-container.select2.direction-up .ui-select-dropdown .select2-search {
- margin-top: 4px; /* FIXME hardcoded value :-/ */
+ margin-top: 4px; /* FIXME hardcoded value :-/ */
}
-.ui-select-container[theme="select2"].direction-up.select2-dropdown-open .ui-select-match,
+.ui-select-container[theme='select2'].direction-up.select2-dropdown-open .ui-select-match,
.ui-select-container.select2.direction-up.select2-dropdown-open .ui-select-match {
- border-bottom-color: $euiColorPrimary;
+ border-bottom-color: $euiColorPrimary;
}
-.ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden,
-.ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden input{
- opacity: 0;
- height: 0;
- min-height: 0;
- padding: 0;
- margin: 0;
- border:0;
+.ui-select-container[theme='select2'] .ui-select-dropdown .ui-select-search-hidden,
+.ui-select-container[theme='select2'] .ui-select-dropdown .ui-select-search-hidden input {
+ opacity: 0;
+ height: 0;
+ min-height: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
}
/* Bootstrap theme */
@@ -133,12 +129,12 @@ body > .select2-container.open {
}
.ui-select-bootstrap .ui-select-search-hidden {
- opacity: 0;
- height: 0;
- min-height: 0;
- padding: 0;
- margin: 0;
- border:0;
+ opacity: 0;
+ height: 0;
+ min-height: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
}
.ui-select-bootstrap > .ui-select-match > .btn {
@@ -213,7 +209,7 @@ body > .ui-select-bootstrap.open {
}
.ui-select-multiple:hover .ui-select-match-item.dropping-before:before {
- content: "";
+ content: '';
position: absolute;
top: 0;
right: 100%;
@@ -223,7 +219,7 @@ body > .ui-select-bootstrap.open {
}
.ui-select-multiple:hover .ui-select-match-item.dropping-after:after {
- content: "";
+ content: '';
position: absolute;
top: 0;
left: 100%;
@@ -232,7 +228,7 @@ body > .ui-select-bootstrap.open {
border-right: 1px solid $euiColorPrimary;
}
-.ui-select-bootstrap .ui-select-choices-row>span {
+.ui-select-bootstrap .ui-select-choices-row > span {
@include euiFontSizeS;
@include euiTextTruncate;
font-weight: inherit;
@@ -251,45 +247,44 @@ body > .ui-select-bootstrap.open {
}
}
-
-.ui-select-bootstrap .ui-select-choices-row.active>span {
- color: $euiTextColor;
- text-decoration: none;
- outline: 0;
- background-color: $euiFocusBackgroundColor;
+.ui-select-bootstrap .ui-select-choices-row.active > span {
+ color: $euiTextColor;
+ text-decoration: none;
+ outline: 0;
+ background-color: $euiFocusBackgroundColor;
}
-.ui-select-bootstrap .ui-select-choices-row.disabled>span,
-.ui-select-bootstrap .ui-select-choices-row.active.disabled>span {
- color: $euiButtonColorDisabled;
- cursor: not-allowed;
- background-color: transparent;
+.ui-select-bootstrap .ui-select-choices-row.disabled > span,
+.ui-select-bootstrap .ui-select-choices-row.active.disabled > span {
+ color: $euiButtonColorDisabled;
+ cursor: not-allowed;
+ background-color: transparent;
}
/* fix hide/show angular animation */
.ui-select-match.ng-hide-add,
.ui-select-search.ng-hide-add {
- display: none !important;
+ display: none !important;
}
/* Mark invalid Bootstrap */
.ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match {
- border-color: $euiColorDanger;
+ border-color: $euiColorDanger;
}
/* Handle up direction Bootstrap */
-.ui-select-container[theme="bootstrap"].direction-up .ui-select-dropdown {
+.ui-select-container[theme='bootstrap'].direction-up .ui-select-dropdown {
@include euiBottomShadowMedium;
}
.ui-select-bootstrap .ui-select-match-text {
- width: 100%;
- padding-right: 1em;
+ width: 100%;
+ padding-right: 1em;
}
.ui-select-bootstrap .ui-select-match-text span {
- display: inline-block;
- width: 100%;
- overflow: hidden;
+ display: inline-block;
+ width: 100%;
+ overflow: hidden;
}
.ui-select-bootstrap .ui-select-toggle > a.btn {
position: absolute;
@@ -300,17 +295,17 @@ body > .ui-select-bootstrap.open {
/* Spinner */
.ui-select-refreshing {
- position: absolute;
- right: 0;
- padding: 8px 27px;
- top: 1px;
- display: inline-block;
- font-family: 'Glyphicons Halflings';
- font-style: normal;
- font-weight: normal;
- line-height: 1;
- -webkit-font-smoothing:antialiased;
- }
+ position: absolute;
+ right: 0;
+ padding: 8px 27px;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+}
@-webkit-keyframes ui-select-spin {
0% {
@@ -342,7 +337,6 @@ body > .ui-select-bootstrap.open {
-webkit-animation: none 0s;
}
-
// Other Custom
/**
diff --git a/src/legacy/ui/public/vis/__tests__/_agg_config.js b/src/legacy/ui/public/vis/__tests__/_agg_config.js
index 9b0398cf8853e..559124e20c10a 100644
--- a/src/legacy/ui/public/vis/__tests__/_agg_config.js
+++ b/src/legacy/ui/public/vis/__tests__/_agg_config.js
@@ -463,7 +463,7 @@ describe('AggConfig', function () {
});
it('returns the field\'s formatter', function () {
- expect(vis.aggs.aggs[0].fieldFormatter()).to.be(vis.aggs.aggs[0].getField().format.getConverterFor());
+ expect(vis.aggs.aggs[0].fieldFormatter().toString()).to.be(vis.aggs.aggs[0].getField().format.getConverterFor().toString());
});
it('returns the string format if the field does not have a format', function () {
@@ -484,7 +484,7 @@ describe('AggConfig', function () {
it('returns the html converter if "html" is passed in', function () {
const field = indexPattern.fields.getByName('bytes');
- expect(vis.aggs.aggs[0].fieldFormatter('html')).to.be(field.format.getConverterFor('html'));
+ expect(vis.aggs.aggs[0].fieldFormatter('html').toString()).to.be(field.format.getConverterFor('html').toString());
});
});
});
diff --git a/src/legacy/ui/public/vis/components/tooltip/_tooltip.scss b/src/legacy/ui/public/vis/components/tooltip/_tooltip.scss
index 451ecc80844dd..5a30ded7c2e5b 100644
--- a/src/legacy/ui/public/vis/components/tooltip/_tooltip.scss
+++ b/src/legacy/ui/public/vis/components/tooltip/_tooltip.scss
@@ -1,6 +1,3 @@
-@import '@elastic/eui/src/components/tool_tip/variables';
-@import '@elastic/eui/src/components/tool_tip/mixins';
-
.visTooltip,
.visTooltip__sizingClone {
@include euiToolTipStyle('s');
diff --git a/src/legacy/ui/public/vis/editors/default/_sidebar.scss b/src/legacy/ui/public/vis/editors/default/_sidebar.scss
index 5a8a0aabad565..e6b75b1a1f783 100644
--- a/src/legacy/ui/public/vis/editors/default/_sidebar.scss
+++ b/src/legacy/ui/public/vis/editors/default/_sidebar.scss
@@ -1,5 +1,3 @@
-@import '@elastic/eui/src/components/form/variables';
-
//
// LAYOUT
//
@@ -44,7 +42,6 @@
}
}
-
/**
* 1. TODO: Override bootstrap styles. Remove !important once we're rid of bootstrap.
*/
@@ -97,7 +94,7 @@
margin-top: $euiSizeS;
}
- label:not([class^="eui"]) {
+ label:not([class^='eui']) {
@include __legacyLabelStyles__bad;
display: block;
}
@@ -169,7 +166,7 @@
.visEditorSidebar__aggGroupAccordionButtonContent {
font-size: $euiFontSizeS;
- span {
+ span {
color: $euiColorDarkShade;
}
}
diff --git a/src/legacy/ui/public/vis/editors/default/default.html b/src/legacy/ui/public/vis/editors/default/default.html
index 2a759815f57f2..60fcbafdb88f5 100644
--- a/src/legacy/ui/public/vis/editors/default/default.html
+++ b/src/legacy/ui/public/vis/editors/default/default.html
@@ -11,6 +11,7 @@
diff --git a/src/legacy/ui/public/vis/editors/default/default.js b/src/legacy/ui/public/vis/editors/default/default.js
index 43d2962df0a1e..9df866d29a8a2 100644
--- a/src/legacy/ui/public/vis/editors/default/default.js
+++ b/src/legacy/ui/public/vis/editors/default/default.js
@@ -33,12 +33,11 @@ import { keyCodes } from '@elastic/eui';
import { parentPipelineAggHelper } from 'ui/agg_types/metrics/lib/parent_pipeline_agg_helper';
import { DefaultEditorSize } from '../../editor_size';
-import { VisEditorTypesRegistryProvider } from '../../../registry/vis_editor_types';
import { AggGroupNames } from './agg_groups';
import { start as embeddables } from '../../../../../core_plugins/embeddable_api/public/np_ready/public/legacy';
-const defaultEditor = function ($rootScope, $compile, getAppState) {
+const defaultEditor = function ($rootScope, $compile) {
return class DefaultEditor {
static key = 'default';
@@ -58,7 +57,7 @@ const defaultEditor = function ($rootScope, $compile, getAppState) {
}
}
- render({ uiState, timeRange, filters, query }) {
+ render({ uiState, timeRange, filters, query, appState }) {
let $scope;
const updateScope = () => {
@@ -161,7 +160,7 @@ const defaultEditor = function ($rootScope, $compile, getAppState) {
this._handler = await embeddables.getEmbeddableFactory('visualization').createFromObject(this.savedObj, {
uiState: uiState,
- appState: getAppState(),
+ appState,
timeRange: timeRange,
filters: filters || [],
query: query,
@@ -195,6 +194,4 @@ const defaultEditor = function ($rootScope, $compile, getAppState) {
};
};
-VisEditorTypesRegistryProvider.register(defaultEditor);
-
export { defaultEditor };
diff --git a/src/legacy/ui/ui_exports/ui_export_defaults.js b/src/legacy/ui/ui_exports/ui_export_defaults.js
index 291d9feea3c40..80bee41175771 100644
--- a/src/legacy/ui/ui_exports/ui_export_defaults.js
+++ b/src/legacy/ui/ui_exports/ui_export_defaults.js
@@ -50,12 +50,6 @@ export const UI_EXPORT_DEFAULTS = {
fieldFormatEditors: [
'ui/field_editor/components/field_format_editor/register'
],
- visEditorTypes: [
- 'ui/vis/editors/default/default',
- ],
- embeddableFactories: [
- 'plugins/kibana/visualize/embeddable/visualize_embeddable_factory',
- ],
search: [
'ui/courier/search_strategy/default_search_strategy',
],
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx
index 684aa93779bc1..021a1a9d1e64a 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx
@@ -90,6 +90,8 @@ export type DashboardReactContext = KibanaReactContext {
public readonly type = DASHBOARD_CONTAINER_TYPE;
+ public renderEmpty?: undefined | (() => React.ReactNode);
+
constructor(
initialInput: DashboardContainerInput,
private readonly options: DashboardContainerOptions,
@@ -124,7 +126,7 @@ export class DashboardContainer extends Container
-
+
,
dom
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss b/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss
index 24b813ec58964..0bd356522c7fa 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss
@@ -34,7 +34,7 @@
.dshLayout-isMaximizedPanel {
height: 100% !important; /* 1. */
width: 100%;
- position: absolute;
+ position: absolute !important;
}
/**
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx
index a2f7b8dc28fb0..e3d9b8552f060 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx
@@ -121,6 +121,24 @@ test('renders DashboardViewport with no visualizations', () => {
component.unmount();
});
+test('renders DashboardEmptyScreen', () => {
+ const renderEmptyScreen = jest.fn();
+ const { props, options } = getProps({ renderEmpty: renderEmptyScreen });
+ props.container.updateInput({ isEmptyState: true });
+ const component = mount(
+
+
+
+
+
+ );
+ const dashboardEmptyScreenDiv = component.find('.dshDashboardEmptyScreen');
+ expect(dashboardEmptyScreenDiv.length).toBe(1);
+ expect(renderEmptyScreen).toHaveBeenCalled();
+
+ component.unmount();
+});
+
test('renders exit full screen button when in full screen mode', async () => {
const { props, options } = getProps();
props.container.updateInput({ isFullScreenMode: true });
@@ -153,6 +171,39 @@ test('renders exit full screen button when in full screen mode', async () => {
component.unmount();
});
+test('renders exit full screen button when in full screen mode and empty screen', async () => {
+ const renderEmptyScreen = jest.fn();
+ renderEmptyScreen.mockReturnValue(React.createElement('div'));
+ const { props, options } = getProps({ renderEmpty: renderEmptyScreen });
+ props.container.updateInput({ isEmptyState: true, isFullScreenMode: true });
+ const component = mount(
+
+
+
+
+
+ );
+ expect(
+ (component
+ .find('.dshDashboardEmptyScreen')
+ .childAt(0)
+ .type() as any).name
+ ).toBe('ExitFullScreenButton');
+
+ props.container.updateInput({ isFullScreenMode: false });
+ component.update();
+ await nextTick();
+
+ expect(
+ (component
+ .find('.dshDashboardEmptyScreen')
+ .childAt(0)
+ .type() as any).name
+ ).not.toBe('ExitFullScreenButton');
+
+ component.unmount();
+});
+
test('DashboardViewport unmount unsubscribes', async done => {
const { props, options } = getProps();
const component = mount(
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx
index 13407e5e33725..e7fd379898dd1 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx
@@ -26,6 +26,7 @@ import { context } from '../../../../kibana_react/public';
export interface DashboardViewportProps {
container: DashboardContainer;
+ renderEmpty?: () => React.ReactNode;
}
interface State {
@@ -34,6 +35,7 @@ interface State {
title: string;
description?: string;
panels: { [key: string]: PanelState };
+ isEmptyState?: boolean;
}
export class DashboardViewport extends React.Component {
@@ -44,26 +46,40 @@ export class DashboardViewport extends React.Component {
- const { isFullScreenMode, useMargins, title, description } = this.props.container.getInput();
+ const {
+ isFullScreenMode,
+ useMargins,
+ title,
+ description,
+ isEmptyState,
+ } = this.props.container.getInput();
if (this.mounted) {
this.setState({
isFullScreenMode,
description,
useMargins,
title,
+ isEmptyState,
});
}
});
@@ -82,19 +98,33 @@ export class DashboardViewport extends React.Component
+ {isFullScreenMode && (
+
+ )}
+ {renderEmpty && renderEmpty()}
+
+ );
+ }
+
+ private renderContainerScreen() {
const { container } = this.props;
+ const { isFullScreenMode, panels, title, description, useMargins } = this.state;
return (
- {this.state.isFullScreenMode && (
+ {isFullScreenMode && (
@@ -103,4 +133,13 @@ export class DashboardViewport extends React.Component
);
}
+
+ public render() {
+ return (
+
+ {this.state.isEmptyState ? this.renderEmptyScreen() : null}
+ {this.renderContainerScreen()}
+
+ );
+ }
}
diff --git a/src/plugins/data/common/es_query/__fixtures__/index_pattern_response.ts b/src/plugins/data/common/es_query/__fixtures__/index_pattern_response.ts
new file mode 100644
index 0000000000000..1784a2650a95a
--- /dev/null
+++ b/src/plugins/data/common/es_query/__fixtures__/index_pattern_response.ts
@@ -0,0 +1,322 @@
+/*
+ * 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 indexPatternResponse = {
+ id: 'logstash-*',
+ title: 'logstash-*',
+ fields: [
+ {
+ name: 'bytes',
+ type: 'number',
+ esTypes: ['long'],
+ count: 10,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'ssl',
+ type: 'boolean',
+ esTypes: ['boolean'],
+ count: 20,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: '@timestamp',
+ type: 'date',
+ esTypes: ['date'],
+ count: 30,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'time',
+ type: 'date',
+ esTypes: ['date'],
+ count: 30,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: '@tags',
+ type: 'string',
+ esTypes: ['keyword'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'utc_time',
+ type: 'date',
+ esTypes: ['date'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'phpmemory',
+ type: 'number',
+ esTypes: ['integer'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'ip',
+ type: 'ip',
+ esTypes: ['ip'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'request_body',
+ type: 'attachment',
+ esTypes: ['attachment'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'point',
+ type: 'geo_point',
+ esTypes: ['geo_point'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'area',
+ type: 'geo_shape',
+ esTypes: ['geo_shape'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'hashed',
+ type: 'murmur3',
+ esTypes: ['murmur3'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ name: 'geo.coordinates',
+ type: 'geo_point',
+ esTypes: ['geo_point'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'extension',
+ type: 'string',
+ esTypes: ['keyword'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'machine.os',
+ type: 'string',
+ esTypes: ['text'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'machine.os.raw',
+ type: 'string',
+ esTypes: ['keyword'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: { multi: { parent: 'machine.os' } },
+ },
+ {
+ name: 'geo.src',
+ type: 'string',
+ esTypes: ['keyword'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: '_id',
+ type: 'string',
+ esTypes: ['_id'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: '_type',
+ type: 'string',
+ esTypes: ['_type'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: '_source',
+ type: '_source',
+ esTypes: ['_source'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'non-filterable',
+ type: 'string',
+ esTypes: ['text'],
+ count: 0,
+ scripted: false,
+ searchable: false,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'non-sortable',
+ type: 'string',
+ esTypes: ['text'],
+ count: 0,
+ scripted: false,
+ searchable: false,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ name: 'custom_user_field',
+ type: 'conflict',
+ esTypes: ['long', 'text'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ name: 'script string',
+ type: 'string',
+ count: 0,
+ scripted: true,
+ script: "'i am a string'",
+ lang: 'expression',
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'script number',
+ type: 'number',
+ count: 0,
+ scripted: true,
+ script: '1234',
+ lang: 'expression',
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'script date',
+ type: 'date',
+ count: 0,
+ scripted: true,
+ script: '1234',
+ lang: 'painless',
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'script murmur3',
+ type: 'murmur3',
+ count: 0,
+ scripted: true,
+ script: '1234',
+ lang: 'expression',
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ name: 'nestedField.child',
+ type: 'string',
+ esTypes: ['text'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ subType: { nested: { path: 'nestedField' } },
+ },
+ {
+ name: 'nestedField.nestedChild.doublyNestedChild',
+ type: 'string',
+ esTypes: ['text'],
+ count: 0,
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ subType: { nested: { path: 'nestedField.nestedChild' } },
+ },
+ ],
+};
diff --git a/src/plugins/data/common/es_query/es_query/from_filters.test.ts b/src/plugins/data/common/es_query/es_query/from_filters.test.ts
index 8c1d990c389b8..a93a91a42dbf3 100644
--- a/src/plugins/data/common/es_query/es_query/from_filters.test.ts
+++ b/src/plugins/data/common/es_query/es_query/from_filters.test.ts
@@ -144,5 +144,30 @@ describe('build query', () => {
expect(result.filter).toEqual(expectedESQueries);
});
+
+ test('should wrap filters targeting nested fields in a nested query', () => {
+ const filters = [
+ {
+ exists: { field: 'nestedField.child' },
+ meta: { type: 'exists', alias: '', disabled: false, negate: false },
+ },
+ ];
+
+ const expectedESQueries = [
+ {
+ nested: {
+ path: 'nestedField',
+ query: {
+ exists: {
+ field: 'nestedField.child',
+ },
+ },
+ },
+ },
+ ];
+
+ const result = buildQueryFromFilters(filters, indexPattern);
+ expect(result.filter).toEqual(expectedESQueries);
+ });
});
});
diff --git a/src/plugins/data/common/es_query/es_query/from_filters.ts b/src/plugins/data/common/es_query/es_query/from_filters.ts
index e33040485bf47..ed91d391fc1fd 100644
--- a/src/plugins/data/common/es_query/es_query/from_filters.ts
+++ b/src/plugins/data/common/es_query/es_query/from_filters.ts
@@ -21,6 +21,7 @@ import { migrateFilter } from './migrate_filter';
import { filterMatchesIndex } from './filter_matches_index';
import { Filter, cleanFilter, isFilterDisabled } from '../filters';
import { IIndexPattern } from '../../index_patterns';
+import { handleNestedFilter } from './handle_nested_filter';
/**
* Create a filter that can be reversed for filters with negate set
@@ -59,20 +60,22 @@ export const buildQueryFromFilters = (
) => {
filters = filters.filter(filter => filter && !isFilterDisabled(filter));
- return {
- must: [],
- filter: filters
- .filter(filterNegate(false))
+ const filtersToESQueries = (negate: boolean) => {
+ return filters
+ .filter(filterNegate(negate))
.filter(filter => !ignoreFilterIfFieldNotInIndex || filterMatchesIndex(filter, indexPattern))
+ .map(filter => {
+ return migrateFilter(filter, indexPattern);
+ })
+ .map(filter => handleNestedFilter(filter, indexPattern))
.map(translateToQuery)
- .map(cleanFilter)
- .map(filter => migrateFilter(filter, indexPattern)),
+ .map(cleanFilter);
+ };
+
+ return {
+ must: [],
+ filter: filtersToESQueries(false),
should: [],
- must_not: filters
- .filter(filterNegate(true))
- .filter(filter => !ignoreFilterIfFieldNotInIndex || filterMatchesIndex(filter, indexPattern))
- .map(translateToQuery)
- .map(cleanFilter)
- .map(filter => migrateFilter(filter, indexPattern)),
+ must_not: filtersToESQueries(true),
};
};
diff --git a/src/plugins/data/common/es_query/es_query/handle_nested_filter.test.ts b/src/plugins/data/common/es_query/es_query/handle_nested_filter.test.ts
new file mode 100644
index 0000000000000..594b2641c39be
--- /dev/null
+++ b/src/plugins/data/common/es_query/es_query/handle_nested_filter.test.ts
@@ -0,0 +1,91 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { handleNestedFilter } from './handle_nested_filter';
+import { fields } from '../../index_patterns/mocks';
+import { buildPhraseFilter, buildQueryFilter } from '../filters';
+import { IFieldType, IIndexPattern } from '../../index_patterns';
+
+describe('handleNestedFilter', function() {
+ const indexPattern: IIndexPattern = ({
+ id: 'logstash-*',
+ fields,
+ } as unknown) as IIndexPattern;
+
+ it("should return the filter's query wrapped in nested query if the target field is nested", () => {
+ const field = getField('nestedField.child');
+ const filter = buildPhraseFilter(field!, 'foo', indexPattern);
+ const result = handleNestedFilter(filter, indexPattern);
+ expect(result).toEqual({
+ meta: {
+ index: 'logstash-*',
+ },
+ nested: {
+ path: 'nestedField',
+ query: {
+ match_phrase: {
+ 'nestedField.child': 'foo',
+ },
+ },
+ },
+ });
+ });
+
+ it('should return filter untouched if it does not target a nested field', () => {
+ const field = getField('extension');
+ const filter = buildPhraseFilter(field!, 'jpg', indexPattern);
+ const result = handleNestedFilter(filter, indexPattern);
+ expect(result).toBe(filter);
+ });
+
+ it('should return filter untouched if it does not target a field from the given index pattern', () => {
+ const field = { ...getField('extension'), name: 'notarealfield' };
+ const filter = buildPhraseFilter(field as IFieldType, 'jpg', indexPattern);
+ const result = handleNestedFilter(filter, indexPattern);
+ expect(result).toBe(filter);
+ });
+
+ it('should return filter untouched if no index pattern is provided', () => {
+ const field = getField('extension');
+ const filter = buildPhraseFilter(field!, 'jpg', indexPattern);
+ const result = handleNestedFilter(filter);
+ expect(result).toBe(filter);
+ });
+
+ it('should return the filter untouched if a target field cannot be determined', () => {
+ // for example, we don't support query_string queries
+ const filter = buildQueryFilter(
+ {
+ query: {
+ query_string: {
+ query: 'response:200',
+ },
+ },
+ },
+ 'logstash-*',
+ 'foo'
+ );
+ const result = handleNestedFilter(filter);
+ expect(result).toBe(filter);
+ });
+
+ function getField(name: string) {
+ return indexPattern.fields.find(field => field.name === name);
+ }
+});
diff --git a/src/plugins/data/common/es_query/es_query/handle_nested_filter.ts b/src/plugins/data/common/es_query/es_query/handle_nested_filter.ts
new file mode 100644
index 0000000000000..27be7925fe00c
--- /dev/null
+++ b/src/plugins/data/common/es_query/es_query/handle_nested_filter.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 { getFilterField, cleanFilter, Filter } from '../filters';
+import { IIndexPattern } from '../../index_patterns';
+
+export const handleNestedFilter = (filter: Filter, indexPattern?: IIndexPattern) => {
+ if (!indexPattern) return filter;
+
+ const fieldName = getFilterField(filter);
+ if (!fieldName) {
+ return filter;
+ }
+
+ const field = indexPattern.fields.find(indexPatternField => indexPatternField.name === fieldName);
+ if (!field || !field.subType || !field.subType.nested || !field.subType.nested.path) {
+ return filter;
+ }
+
+ const query = cleanFilter(filter);
+
+ return {
+ meta: filter.meta,
+ nested: {
+ path: field.subType.nested.path,
+ query: query.query || query,
+ },
+ };
+};
diff --git a/src/plugins/data/common/es_query/es_query/migrate_filter.test.ts b/src/plugins/data/common/es_query/es_query/migrate_filter.test.ts
index e01240da87543..698d7bb48e685 100644
--- a/src/plugins/data/common/es_query/es_query/migrate_filter.test.ts
+++ b/src/plugins/data/common/es_query/es_query/migrate_filter.test.ts
@@ -23,26 +23,32 @@ import { PhraseFilter, MatchAllFilter } from '../filters';
describe('migrateFilter', function() {
const oldMatchPhraseFilter = ({
- match: {
- fieldFoo: {
- query: 'foobar',
- type: 'phrase',
+ query: {
+ match: {
+ fieldFoo: {
+ query: 'foobar',
+ type: 'phrase',
+ },
},
},
+ meta: {},
} as unknown) as DeprecatedMatchPhraseFilter;
const newMatchPhraseFilter = ({
- match_phrase: {
- fieldFoo: {
- query: 'foobar',
+ query: {
+ match_phrase: {
+ fieldFoo: {
+ query: 'foobar',
+ },
},
},
+ meta: {},
} as unknown) as PhraseFilter;
it('should migrate match filters of type phrase', function() {
const migratedFilter = migrateFilter(oldMatchPhraseFilter, undefined);
- expect(isEqual(migratedFilter, newMatchPhraseFilter)).toBe(true);
+ expect(migratedFilter).toEqual(newMatchPhraseFilter);
});
it('should not modify the original filter', function() {
diff --git a/src/plugins/data/common/es_query/es_query/migrate_filter.ts b/src/plugins/data/common/es_query/es_query/migrate_filter.ts
index fdc40768ebe41..22fbfe0e1ab08 100644
--- a/src/plugins/data/common/es_query/es_query/migrate_filter.ts
+++ b/src/plugins/data/common/es_query/es_query/migrate_filter.ts
@@ -22,31 +22,27 @@ import { getConvertedValueForField } from '../filters';
import { Filter } from '../filters';
import { IIndexPattern } from '../../index_patterns';
-/** @deprecated
- * see https://github.com/elastic/elasticsearch/pull/17508
- * */
export interface DeprecatedMatchPhraseFilter extends Filter {
- match: {
- [field: string]: {
- query: any;
- type: 'phrase';
+ query: {
+ match: {
+ [field: string]: {
+ query: any;
+ type: 'phrase';
+ };
};
};
}
-/** @deprecated
- * see https://github.com/elastic/elasticsearch/pull/17508
- * */
-function isMatchPhraseFilter(filter: any): filter is DeprecatedMatchPhraseFilter {
- const fieldName = filter.match && Object.keys(filter.match)[0];
+function isDeprecatedMatchPhraseFilter(filter: any): filter is DeprecatedMatchPhraseFilter {
+ const fieldName = filter.query && filter.query.match && Object.keys(filter.query.match)[0];
- return Boolean(fieldName && get(filter, ['match', fieldName, 'type']) === 'phrase');
+ return Boolean(fieldName && get(filter, ['query', 'match', fieldName, 'type']) === 'phrase');
}
export function migrateFilter(filter: Filter, indexPattern?: IIndexPattern) {
- if (isMatchPhraseFilter(filter)) {
- const fieldName = Object.keys(filter.match)[0];
- const params: Record = get(filter, ['match', fieldName]);
+ if (isDeprecatedMatchPhraseFilter(filter)) {
+ const fieldName = Object.keys(filter.query.match)[0];
+ const params: Record = get(filter, ['query', 'match', fieldName]);
if (indexPattern) {
const field = indexPattern.fields.find(f => f.name === fieldName);
@@ -55,8 +51,11 @@ export function migrateFilter(filter: Filter, indexPattern?: IIndexPattern) {
}
}
return {
- match_phrase: {
- [fieldName]: omit(params, 'type'),
+ ...filter,
+ query: {
+ match_phrase: {
+ [fieldName]: omit(params, 'type'),
+ },
},
};
}
diff --git a/src/plugins/data/common/es_query/filters/exists_filter.test.ts b/src/plugins/data/common/es_query/filters/exists_filter.test.ts
new file mode 100644
index 0000000000000..af52192dd85e4
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/exists_filter.test.ts
@@ -0,0 +1,37 @@
+/*
+ * 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 { buildExistsFilter, getExistsFilterField } from './exists_filter';
+import { IIndexPattern } from '../../index_patterns';
+import { fields } from '../../index_patterns/fields/fields.mocks.ts';
+
+describe('exists filter', function() {
+ const indexPattern: IIndexPattern = ({
+ fields,
+ } as unknown) as IIndexPattern;
+
+ describe('getExistsFilterField', function() {
+ it('should return the name of the field an exists query is targeting', () => {
+ const field = indexPattern.fields.find(patternField => patternField.name === 'extension');
+ const filter = buildExistsFilter(field!, indexPattern);
+ const result = getExistsFilterField(filter);
+ expect(result).toBe('extension');
+ });
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/exists_filter.ts b/src/plugins/data/common/es_query/filters/exists_filter.ts
index a20a4f0634766..035983dc446dc 100644
--- a/src/plugins/data/common/es_query/filters/exists_filter.ts
+++ b/src/plugins/data/common/es_query/filters/exists_filter.ts
@@ -33,6 +33,10 @@ export type ExistsFilter = Filter & {
export const isExistsFilter = (filter: any): filter is ExistsFilter => filter && filter.exists;
+export const getExistsFilterField = (filter: ExistsFilter) => {
+ return filter.exists && filter.exists.field;
+};
+
export const buildExistsFilter = (field: IFieldType, indexPattern: IIndexPattern) => {
return {
meta: {
diff --git a/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.test.ts b/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.test.ts
new file mode 100644
index 0000000000000..63c3a59044c1f
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.test.ts
@@ -0,0 +1,47 @@
+/*
+ * 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 { getGeoBoundingBoxFilterField } from './geo_bounding_box_filter';
+
+describe('geo_bounding_box filter', function() {
+ describe('getGeoBoundingBoxFilterField', function() {
+ it('should return the name of the field a geo_bounding_box query is targeting', () => {
+ const filter = {
+ geo_bounding_box: {
+ geoPointField: {
+ bottom_right: { lat: 1, lon: 1 },
+ top_left: { lat: 1, lon: 1 },
+ },
+ ignore_unmapped: true,
+ },
+ meta: {
+ disabled: false,
+ negate: false,
+ alias: null,
+ params: {
+ bottom_right: { lat: 1, lon: 1 },
+ top_left: { lat: 1, lon: 1 },
+ },
+ },
+ };
+ const result = getGeoBoundingBoxFilterField(filter);
+ expect(result).toBe('geoPointField');
+ });
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.ts b/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.ts
index f4673af96b2cd..619903954ff55 100644
--- a/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.ts
+++ b/src/plugins/data/common/es_query/filters/geo_bounding_box_filter.ts
@@ -33,3 +33,10 @@ export type GeoBoundingBoxFilter = Filter & {
export const isGeoBoundingBoxFilter = (filter: any): filter is GeoBoundingBoxFilter =>
filter && filter.geo_bounding_box;
+
+export const getGeoBoundingBoxFilterField = (filter: GeoBoundingBoxFilter) => {
+ return (
+ filter.geo_bounding_box &&
+ Object.keys(filter.geo_bounding_box).find(key => key !== 'ignore_unmapped')
+ );
+};
diff --git a/src/plugins/data/common/es_query/filters/geo_polygon_filter.test.ts b/src/plugins/data/common/es_query/filters/geo_polygon_filter.test.ts
new file mode 100644
index 0000000000000..ba8e43b0cea85
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/geo_polygon_filter.test.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 { getGeoPolygonFilterField } from './geo_polygon_filter';
+
+describe('geo_polygon filter', function() {
+ describe('getGeoPolygonFilterField', function() {
+ it('should return the name of the field a geo_polygon query is targeting', () => {
+ const filter = {
+ geo_polygon: {
+ geoPointField: {
+ points: [{ lat: 1, lon: 1 }],
+ },
+ ignore_unmapped: true,
+ },
+ meta: {
+ disabled: false,
+ negate: false,
+ alias: null,
+ params: {
+ points: [{ lat: 1, lon: 1 }],
+ },
+ },
+ };
+ const result = getGeoPolygonFilterField(filter);
+ expect(result).toBe('geoPointField');
+ });
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/geo_polygon_filter.ts b/src/plugins/data/common/es_query/filters/geo_polygon_filter.ts
index 4cf82a92d2cef..03367feb83ee4 100644
--- a/src/plugins/data/common/es_query/filters/geo_polygon_filter.ts
+++ b/src/plugins/data/common/es_query/filters/geo_polygon_filter.ts
@@ -32,3 +32,9 @@ export type GeoPolygonFilter = Filter & {
export const isGeoPolygonFilter = (filter: any): filter is GeoPolygonFilter =>
filter && filter.geo_polygon;
+
+export const getGeoPolygonFilterField = (filter: GeoPolygonFilter) => {
+ return (
+ filter.geo_polygon && Object.keys(filter.geo_polygon).find(key => key !== 'ignore_unmapped')
+ );
+};
diff --git a/src/plugins/data/common/es_query/filters/get_filter_field.test.ts b/src/plugins/data/common/es_query/filters/get_filter_field.test.ts
new file mode 100644
index 0000000000000..2fc8ffef9713b
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/get_filter_field.test.ts
@@ -0,0 +1,54 @@
+/*
+ * 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 { buildPhraseFilter } from './phrase_filter';
+import { buildQueryFilter } from './query_string_filter';
+import { getFilterField } from './get_filter_field';
+import { IIndexPattern } from '../../index_patterns';
+import { fields } from '../../index_patterns/fields/fields.mocks.ts';
+
+describe('getFilterField', function() {
+ const indexPattern: IIndexPattern = ({
+ id: 'logstash-*',
+ fields,
+ } as unknown) as IIndexPattern;
+
+ it('should return the field name from known filter types that target a specific field', () => {
+ const field = indexPattern.fields.find(patternField => patternField.name === 'extension');
+ const filter = buildPhraseFilter(field!, 'jpg', indexPattern);
+ const result = getFilterField(filter);
+ expect(result).toBe('extension');
+ });
+
+ it('should return undefined for filters that do not target a specific field', () => {
+ const filter = buildQueryFilter(
+ {
+ query: {
+ query_string: {
+ query: 'response:200 and extension:jpg',
+ },
+ },
+ },
+ indexPattern.id!,
+ ''
+ );
+ const result = getFilterField(filter);
+ expect(result).toBe(undefined);
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/get_filter_field.ts b/src/plugins/data/common/es_query/filters/get_filter_field.ts
new file mode 100644
index 0000000000000..dfb575157d362
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/get_filter_field.ts
@@ -0,0 +1,53 @@
+/*
+ * 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 { Filter } from './meta_filter';
+import { getExistsFilterField, isExistsFilter } from './exists_filter';
+import { getGeoBoundingBoxFilterField, isGeoBoundingBoxFilter } from './geo_bounding_box_filter';
+import { getGeoPolygonFilterField, isGeoPolygonFilter } from './geo_polygon_filter';
+import { getPhraseFilterField, isPhraseFilter } from './phrase_filter';
+import { getPhrasesFilterField, isPhrasesFilter } from './phrases_filter';
+import { getRangeFilterField, isRangeFilter } from './range_filter';
+import { getMissingFilterField, isMissingFilter } from './missing_filter';
+
+export const getFilterField = (filter: Filter) => {
+ if (isExistsFilter(filter)) {
+ return getExistsFilterField(filter);
+ }
+ if (isGeoBoundingBoxFilter(filter)) {
+ return getGeoBoundingBoxFilterField(filter);
+ }
+ if (isGeoPolygonFilter(filter)) {
+ return getGeoPolygonFilterField(filter);
+ }
+ if (isPhraseFilter(filter)) {
+ return getPhraseFilterField(filter);
+ }
+ if (isPhrasesFilter(filter)) {
+ return getPhrasesFilterField(filter);
+ }
+ if (isRangeFilter(filter)) {
+ return getRangeFilterField(filter);
+ }
+ if (isMissingFilter(filter)) {
+ return getMissingFilterField(filter);
+ }
+
+ return;
+};
diff --git a/src/plugins/data/common/es_query/filters/index.ts b/src/plugins/data/common/es_query/filters/index.ts
index 1bd534bf74ff7..403ff2b79b55f 100644
--- a/src/plugins/data/common/es_query/filters/index.ts
+++ b/src/plugins/data/common/es_query/filters/index.ts
@@ -22,6 +22,7 @@ import { Filter } from './meta_filter';
export * from './build_filters';
export * from './get_filter_params';
+export * from './get_filter_field';
export * from './custom_filter';
export * from './exists_filter';
diff --git a/src/plugins/data/common/es_query/filters/missing_filter.test.ts b/src/plugins/data/common/es_query/filters/missing_filter.test.ts
new file mode 100644
index 0000000000000..240d8fb26f3e0
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/missing_filter.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 { getMissingFilterField } from './missing_filter';
+
+describe('missing filter', function() {
+ describe('getMissingFilterField', function() {
+ it('should return the name of the field an missing query is targeting', () => {
+ const filter = {
+ missing: {
+ field: 'extension',
+ },
+ meta: {
+ disabled: false,
+ negate: false,
+ alias: null,
+ },
+ };
+ const result = getMissingFilterField(filter);
+ expect(result).toBe('extension');
+ });
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/missing_filter.ts b/src/plugins/data/common/es_query/filters/missing_filter.ts
index 5411187cbcfd7..c8e1194a8f3cc 100644
--- a/src/plugins/data/common/es_query/filters/missing_filter.ts
+++ b/src/plugins/data/common/es_query/filters/missing_filter.ts
@@ -27,3 +27,7 @@ export type MissingFilter = Filter & {
};
export const isMissingFilter = (filter: any): filter is MissingFilter => filter && filter.missing;
+
+export const getMissingFilterField = (filter: MissingFilter) => {
+ return filter.missing && filter.missing.field;
+};
diff --git a/src/plugins/data/common/es_query/filters/phrase_filter.test.ts b/src/plugins/data/common/es_query/filters/phrase_filter.test.ts
index 3c7d00a80fecf..9f90097e55475 100644
--- a/src/plugins/data/common/es_query/filters/phrase_filter.test.ts
+++ b/src/plugins/data/common/es_query/filters/phrase_filter.test.ts
@@ -17,8 +17,12 @@
* under the License.
*/
-import { buildInlineScriptForPhraseFilter, buildPhraseFilter } from './phrase_filter';
-import { getField } from '../../index_patterns/mocks';
+import {
+ buildInlineScriptForPhraseFilter,
+ buildPhraseFilter,
+ getPhraseFilterField,
+} from './phrase_filter';
+import { fields, getField } from '../../index_patterns/mocks';
import { IIndexPattern } from '../../index_patterns';
describe('Phrase filter builder', () => {
@@ -95,3 +99,16 @@ describe('buildInlineScriptForPhraseFilter', () => {
expect(buildInlineScriptForPhraseFilter(field)).toBe(expected);
});
});
+
+describe('getPhraseFilterField', function() {
+ const indexPattern: IIndexPattern = ({
+ fields,
+ } as unknown) as IIndexPattern;
+
+ it('should return the name of the field a phrase query is targeting', () => {
+ const field = indexPattern.fields.find(patternField => patternField.name === 'extension');
+ const filter = buildPhraseFilter(field!, 'jpg', indexPattern);
+ const result = getPhraseFilterField(filter);
+ expect(result).toBe('extension');
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/phrases_filter.test.ts b/src/plugins/data/common/es_query/filters/phrases_filter.test.ts
new file mode 100644
index 0000000000000..3a121eb9da034
--- /dev/null
+++ b/src/plugins/data/common/es_query/filters/phrases_filter.test.ts
@@ -0,0 +1,37 @@
+/*
+ * 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 { buildPhrasesFilter, getPhrasesFilterField } from './phrases_filter';
+import { IIndexPattern } from '../../index_patterns';
+import { fields } from '../../index_patterns/fields/fields.mocks.ts';
+
+describe('phrases filter', function() {
+ const indexPattern: IIndexPattern = ({
+ fields,
+ } as unknown) as IIndexPattern;
+
+ describe('getPhrasesFilterField', function() {
+ it('should return the name of the field a phrases query is targeting', () => {
+ const field = indexPattern.fields.find(patternField => patternField.name === 'extension');
+ const filter = buildPhrasesFilter(field!, ['jpg', 'png'], indexPattern);
+ const result = getPhrasesFilterField(filter);
+ expect(result).toBe('extension');
+ });
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/phrases_filter.ts b/src/plugins/data/common/es_query/filters/phrases_filter.ts
index f7164f0ad3c83..006e0623be913 100644
--- a/src/plugins/data/common/es_query/filters/phrases_filter.ts
+++ b/src/plugins/data/common/es_query/filters/phrases_filter.ts
@@ -32,7 +32,13 @@ export type PhrasesFilter = Filter & {
};
export const isPhrasesFilter = (filter: any): filter is PhrasesFilter =>
- filter && filter.meta.type === FILTERS.PHRASES;
+ filter?.meta?.type === FILTERS.PHRASES;
+
+export const getPhrasesFilterField = (filter: PhrasesFilter) => {
+ // Phrases is a newer filter type that has always been created via a constructor that ensures
+ // `meta.key` is set to the field name
+ return filter.meta.key;
+};
// Creates a filter where the given field matches one or more of the given values
// params should be an array of values
diff --git a/src/plugins/data/common/es_query/filters/query_string_filter.test.ts b/src/plugins/data/common/es_query/filters/query_string_filter.test.ts
index 4fcb15ccac44a..18285194c6054 100644
--- a/src/plugins/data/common/es_query/filters/query_string_filter.test.ts
+++ b/src/plugins/data/common/es_query/filters/query_string_filter.test.ts
@@ -19,7 +19,7 @@
import { buildQueryFilter } from './query_string_filter';
-describe('Phrase filter builder', () => {
+describe('Query string filter builder', () => {
it('should be a function', () => {
expect(typeof buildQueryFilter).toBe('function');
});
diff --git a/src/plugins/data/common/es_query/filters/range_filter.test.ts b/src/plugins/data/common/es_query/filters/range_filter.test.ts
index 56b63018b5153..45d59c97941b3 100644
--- a/src/plugins/data/common/es_query/filters/range_filter.test.ts
+++ b/src/plugins/data/common/es_query/filters/range_filter.test.ts
@@ -18,8 +18,8 @@
*/
import { each } from 'lodash';
-import { buildRangeFilter, RangeFilter } from './range_filter';
-import { getField } from '../../index_patterns/mocks';
+import { buildRangeFilter, getRangeFilterField, RangeFilter } from './range_filter';
+import { fields, getField } from '../../index_patterns/mocks';
import { IIndexPattern, IFieldType } from '../../index_patterns';
describe('Range filter builder', () => {
@@ -172,3 +172,16 @@ describe('Range filter builder', () => {
});
});
});
+
+describe('getRangeFilterField', function() {
+ const indexPattern: IIndexPattern = ({
+ fields,
+ } as unknown) as IIndexPattern;
+
+ test('should return the name of the field a range query is targeting', () => {
+ const field = indexPattern.fields.find(patternField => patternField.name === 'bytes');
+ const filter = buildRangeFilter(field!, {}, indexPattern);
+ const result = getRangeFilterField(filter);
+ expect(result).toBe('bytes');
+ });
+});
diff --git a/src/plugins/data/common/es_query/filters/range_filter.ts b/src/plugins/data/common/es_query/filters/range_filter.ts
index 3d819bd145fa6..b300539f4280a 100644
--- a/src/plugins/data/common/es_query/filters/range_filter.ts
+++ b/src/plugins/data/common/es_query/filters/range_filter.ts
@@ -88,6 +88,10 @@ export const isScriptedRangeFilter = (filter: any): filter is RangeFilter => {
return hasRangeKeys(params);
};
+export const getRangeFilterField = (filter: RangeFilter) => {
+ return filter.range && Object.keys(filter.range)[0];
+};
+
const formatValue = (field: IFieldType, params: any[]) =>
map(params, (val: any, key: string) => get(operators, key) + format(field, val)).join(' ');
diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json
index bd2bc1bab2a1a..998eaa55858d2 100644
--- a/src/plugins/data/kibana.json
+++ b/src/plugins/data/kibana.json
@@ -2,5 +2,6 @@
"id": "data",
"version": "kibana",
"server": true,
- "ui": true
+ "ui": true,
+ "requiredPlugins": ["uiActions"]
}
diff --git a/src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts
similarity index 84%
rename from src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts
rename to src/plugins/data/public/actions/apply_filter_action.ts
index c65ae3a0ec7b9..b006889637c50 100644
--- a/src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts
+++ b/src/plugins/data/public/actions/apply_filter_action.ts
@@ -18,22 +18,17 @@
*/
import { i18n } from '@kbn/i18n';
-import { CoreStart } from 'src/core/public';
-import { toMountPoint } from '../../../../../../plugins/kibana_react/public';
-import {
- IAction,
- createAction,
- IncompatibleActionError,
-} from '../../../../../../plugins/ui_actions/public';
+import { toMountPoint } from '../../../kibana_react/public';
+import { IAction, createAction, IncompatibleActionError } from '../../../ui_actions/public';
+import { getOverlays, getIndexPatterns } from '../services';
+import { applyFiltersPopover } from '../ui/apply_filters';
import {
esFilters,
FilterManager,
TimefilterContract,
- applyFiltersPopover,
changeTimeFilter,
extractTimeFilter,
- IndexPatternsStart,
-} from '../../../../../../plugins/data/public';
+} from '..';
export const GLOBAL_APPLY_FILTER_ACTION = 'GLOBAL_APPLY_FILTER_ACTION';
@@ -47,10 +42,8 @@ async function isCompatible(context: ActionContext) {
}
export function createFilterAction(
- overlays: CoreStart['overlays'],
filterManager: FilterManager,
- timeFilter: TimefilterContract,
- indexPatternsService: IndexPatternsStart
+ timeFilter: TimefilterContract
): IAction {
return createAction({
type: GLOBAL_APPLY_FILTER_ACTION,
@@ -75,12 +68,12 @@ export function createFilterAction(
if (selectedFilters.length > 1) {
const indexPatterns = await Promise.all(
filters.map(filter => {
- return indexPatternsService.indexPatterns.get(filter.meta.index!);
+ return getIndexPatterns().get(filter.meta.index!);
})
);
const filterSelectionPromise: Promise = new Promise(resolve => {
- const overlay = overlays.openModal(
+ const overlay = getOverlays().openModal(
toMountPoint(
applyFiltersPopover(
filters,
diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts
new file mode 100644
index 0000000000000..5d469606944a1
--- /dev/null
+++ b/src/plugins/data/public/actions/index.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 { GLOBAL_APPLY_FILTER_ACTION, createFilterAction } from './apply_filter_action';
diff --git a/src/plugins/data/public/autocomplete_provider/types.ts b/src/plugins/data/public/autocomplete_provider/types.ts
index 3d34b1bc4a2d2..389057f94144d 100644
--- a/src/plugins/data/public/autocomplete_provider/types.ts
+++ b/src/plugins/data/public/autocomplete_provider/types.ts
@@ -40,6 +40,7 @@ export type GetSuggestions = (args: {
query: string;
selectionStart: number;
selectionEnd: number;
+ signal?: AbortSignal;
}) => Promise;
/** @public **/
diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts
index eca6258099141..e54278698a05a 100644
--- a/src/plugins/data/public/index.ts
+++ b/src/plugins/data/public/index.ts
@@ -18,14 +18,10 @@
*/
import { PluginInitializerContext } from '../../../core/public';
-import { DataPublicPlugin } from './plugin';
-
export function plugin(initializerContext: PluginInitializerContext) {
return new DataPublicPlugin(initializerContext);
}
-export { DataPublicPlugin as Plugin };
-
export * from '../common';
export * from './autocomplete_provider';
@@ -39,3 +35,7 @@ export * from './search';
export * from './query';
export * from './ui';
+
+// Export plugin after all other imports
+import { DataPublicPlugin } from './plugin';
+export { DataPublicPlugin as Plugin };
diff --git a/src/plugins/data/public/index_patterns/fields/field.ts b/src/plugins/data/public/index_patterns/fields/field.ts
index ae17188de8625..c8c8ac1ffd321 100644
--- a/src/plugins/data/public/index_patterns/fields/field.ts
+++ b/src/plugins/data/public/index_patterns/fields/field.ts
@@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n';
// @ts-ignore
import { ObjDefine } from './obj_define';
import { IndexPattern } from '../index_patterns';
-import { getNotifications, getFieldFormats } from '../services';
+import { getNotifications, getFieldFormats } from '../../services';
import {
IFieldType,
getKbnFieldType,
diff --git a/src/plugins/data/public/index_patterns/fields/field_list.ts b/src/plugins/data/public/index_patterns/fields/field_list.ts
index ff6706cec6c34..03214a8c96427 100644
--- a/src/plugins/data/public/index_patterns/fields/field_list.ts
+++ b/src/plugins/data/public/index_patterns/fields/field_list.ts
@@ -24,14 +24,14 @@ import { Field, FieldSpec } from './field';
type FieldMap = Map;
-export interface FieldListInterface extends Array {
+export interface IFieldList extends Array {
getByName(name: Field['name']): Field | undefined;
getByType(type: Field['type']): Field[];
add(field: FieldSpec): void;
remove(field: IFieldType): void;
}
-export class FieldList extends Array implements FieldListInterface {
+export class FieldList extends Array implements IFieldList {
private byName: FieldMap = new Map();
private groups: Map = new Map();
private indexPattern: IndexPattern;
diff --git a/src/plugins/data/public/index_patterns/index.ts b/src/plugins/data/public/index_patterns/index.ts
index e6978e6d3957d..6f4821c391721 100644
--- a/src/plugins/data/public/index_patterns/index.ts
+++ b/src/plugins/data/public/index_patterns/index.ts
@@ -42,7 +42,7 @@ export const indexPatterns = {
formatHitProvider,
};
-export { IndexPatternsService } from './index_patterns_service';
-export { Field, FieldList, FieldListInterface } from './fields';
-export { IndexPattern, IndexPatterns } from './index_patterns';
-export { IndexPatternsStart, IndexPatternsSetup } from './types';
+export { Field, FieldList, IFieldList } from './fields';
+
+// TODO: figure out how to replace IndexPatterns in get_inner_angular.
+export { IndexPattern, IndexPatterns, IndexPatternsContract } from './index_patterns';
diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts
index a0a884454a3f0..f56f94fa8c260 100644
--- a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts
+++ b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts
@@ -26,7 +26,7 @@ import mockLogStashFields from '../../../../../fixtures/logstash_fields';
// @ts-ignore
import { stubbedSavedObjectIndexPattern } from '../../../../../fixtures/stubbed_saved_object_index_pattern';
import { Field } from '../fields';
-import { setNotifications, setFieldFormats } from '../services';
+import { setNotifications, setFieldFormats } from '../../services';
// Temporary disable eslint, will be removed after moving to new platform folder
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts
index 2c93c0aa9dc62..19e465104cf4c 100644
--- a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts
+++ b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts
@@ -32,12 +32,12 @@ import { ES_FIELD_TYPES, KBN_FIELD_TYPES, IIndexPattern, IFieldType } from '../.
import { findByTitle, getRoutes } from '../utils';
import { indexPatterns } from '../';
-import { Field, FieldList, FieldListInterface } from '../fields';
+import { Field, FieldList, IFieldList } from '../fields';
import { createFieldsFetcher } from './_fields_fetcher';
import { formatHitProvider } from './format_hit';
import { flattenHitWrapper } from './flatten_hit';
import { IIndexPatternsApiClient } from './index_patterns_api_client';
-import { getNotifications, getFieldFormats } from '../services';
+import { getNotifications, getFieldFormats } from '../../services';
const MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS = 3;
const type = 'index-pattern';
@@ -50,7 +50,7 @@ export class IndexPattern implements IIndexPattern {
public type?: string;
public fieldFormatMap: any;
public typeMeta: any;
- public fields: FieldListInterface;
+ public fields: IFieldList;
public timeFieldName: string | undefined;
public formatHit: any;
public formatField: any;
diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts
index d6a8e7b20451d..da58881b5b96e 100644
--- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts
+++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { idx } from '@kbn/elastic-idx';
import {
SavedObjectsClientContract,
SimpleSavedObject,
@@ -64,7 +63,7 @@ export class IndexPatterns {
if (!this.savedObjectsCache) {
return [];
}
- return this.savedObjectsCache.map(obj => idx(obj, _ => _.id));
+ return this.savedObjectsCache.map(obj => obj?.id);
};
getTitles = async (refresh: boolean = false): Promise => {
@@ -74,7 +73,7 @@ export class IndexPatterns {
if (!this.savedObjectsCache) {
return [];
}
- return this.savedObjectsCache.map(obj => idx(obj, _ => _.attributes.title));
+ return this.savedObjectsCache.map(obj => obj?.attributes?.title);
};
getFields = async (fields: string[], refresh: boolean = false) => {
@@ -86,7 +85,7 @@ export class IndexPatterns {
}
return this.savedObjectsCache.map((obj: Record) => {
const result: Record = {};
- fields.forEach((f: string) => (result[f] = obj[f] || idx(obj, _ => _.attributes[f])));
+ fields.forEach((f: string) => (result[f] = obj[f] || obj?.attributes?.[f]));
return result;
});
};
@@ -146,3 +145,5 @@ export class IndexPatterns {
return indexPattern.init();
};
}
+
+export type IndexPatternsContract = PublicMethodsOf;
diff --git a/src/plugins/data/public/index_patterns/index_patterns_service.mock.ts b/src/plugins/data/public/index_patterns/index_patterns_service.mock.ts
deleted file mode 100644
index d38e9c76430eb..0000000000000
--- a/src/plugins/data/public/index_patterns/index_patterns_service.mock.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { IndexPatternsService } from './index_patterns_service';
-import { flattenHitWrapper } from './index_patterns';
-import { IndexPatternsSetup } from './types';
-
-type IndexPatternsServiceClientContract = PublicMethodsOf;
-
-const createSetupContractMock = () => {
- // Legacy mock - must be removed before migrating to new platform.
- // Included here because we only want to call `jest.mock` when somebody creates
- // the mock for this contract.
- jest.mock('ui/chrome');
-
- const setupContract: jest.Mocked = {
- FieldList: {} as any,
- flattenHitWrapper: jest.fn().mockImplementation(flattenHitWrapper),
- formatHitProvider: jest.fn(),
- indexPatterns: jest.fn() as any,
- IndexPatternSelect: jest.fn(),
- };
-
- return setupContract;
-};
-
-const createMock = () => {
- const mocked: jest.Mocked = {
- setup: jest.fn(),
- start: jest.fn(),
- stop: jest.fn(),
- };
-
- mocked.setup.mockReturnValue(createSetupContractMock());
- return mocked;
-};
-
-export const indexPatternsServiceMock = {
- create: createMock,
- createSetupContract: createSetupContractMock,
- createStartContract: createSetupContractMock,
-};
diff --git a/src/plugins/data/public/index_patterns/index_patterns_service.ts b/src/plugins/data/public/index_patterns/index_patterns_service.ts
deleted file mode 100644
index 43ba5082ec479..0000000000000
--- a/src/plugins/data/public/index_patterns/index_patterns_service.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import {
- IUiSettingsClient,
- SavedObjectsClientContract,
- HttpServiceBase,
- NotificationsStart,
-} from 'src/core/public';
-import { FieldFormatsStart } from '../field_formats_provider';
-import { setNotifications, setFieldFormats } from './services';
-import { IndexPatterns } from './index_patterns';
-
-export interface IndexPatternDependencies {
- uiSettings: IUiSettingsClient;
- savedObjectsClient: SavedObjectsClientContract;
- http: HttpServiceBase;
- notifications: NotificationsStart;
- fieldFormats: FieldFormatsStart;
-}
-
-/**
- * Index Patterns Service
- *
- * @internal
- */
-export class IndexPatternsService {
- private setupApi: any;
-
- public setup() {
- this.setupApi = {};
-
- return this.setupApi;
- }
-
- public start({
- uiSettings,
- savedObjectsClient,
- http,
- notifications,
- fieldFormats,
- }: IndexPatternDependencies) {
- setNotifications(notifications);
- setFieldFormats(fieldFormats);
-
- return {
- indexPatterns: new IndexPatterns(uiSettings, savedObjectsClient, http),
- };
- }
-
- public stop() {
- // nothing to do here yet
- }
-}
diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts
index 19c21ab9934ef..058e6c0e2f5c5 100644
--- a/src/plugins/data/public/mocks.ts
+++ b/src/plugins/data/public/mocks.ts
@@ -16,10 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { FieldFormatRegisty, Plugin, FieldFormatsStart, FieldFormatsSetup } from '.';
+import {
+ FieldFormatRegisty,
+ Plugin,
+ FieldFormatsStart,
+ FieldFormatsSetup,
+ IndexPatternsContract,
+} from '.';
import { searchSetupMock } from './search/mocks';
import { queryServiceMock } from './query/mocks';
-import { indexPatternsServiceMock } from './index_patterns/index_patterns_service.mock';
export type Setup = jest.Mocked>;
export type Start = jest.Mocked>;
@@ -54,7 +59,6 @@ const createSetupContract = (): Setup => {
search: searchSetupMock,
fieldFormats: fieldFormatsMock as FieldFormatsSetup,
query: querySetupMock,
- indexPatterns: indexPatternsServiceMock.createSetupContract(),
};
return setupContract;
@@ -71,7 +75,7 @@ const createStartContract = (): Start => {
ui: {
IndexPatternSelect: jest.fn(),
},
- indexPatterns: indexPatternsServiceMock.createStartContract(),
+ indexPatterns: {} as IndexPatternsContract,
};
return startContract;
};
diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts
index c018efcad74e6..2a37be7f3f46a 100644
--- a/src/plugins/data/public/plugin.ts
+++ b/src/plugins/data/public/plugin.ts
@@ -19,17 +19,24 @@
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
import { Storage } from '../../kibana_utils/public';
-import { DataPublicPluginSetup, DataPublicPluginStart } from './types';
+import {
+ DataPublicPluginSetup,
+ DataPublicPluginStart,
+ DataSetupDependencies,
+ DataStartDependencies,
+} from './types';
import { AutocompleteProviderRegister } from './autocomplete_provider';
import { getSuggestionsProvider } from './suggestions_provider';
import { SearchService } from './search/search_service';
import { FieldFormatsService } from './field_formats_provider';
import { QueryService } from './query';
import { createIndexPatternSelect } from './ui/index_pattern_select';
-import { IndexPatternsService } from './index_patterns';
+import { IndexPatterns } from './index_patterns';
+import { setNotifications, setFieldFormats, setOverlays, setIndexPatterns } from './services';
+import { createFilterAction, GLOBAL_APPLY_FILTER_ACTION } from './actions';
+import { APPLY_FILTER_TRIGGER } from '../../embeddable/public';
export class DataPublicPlugin implements Plugin {
- private readonly indexPatterns: IndexPatternsService = new IndexPatternsService();
private readonly autocomplete = new AutocompleteProviderRegister();
private readonly searchService: SearchService;
private readonly fieldFormatsService: FieldFormatsService;
@@ -41,23 +48,36 @@ export class DataPublicPlugin implements Plugin(
'Notifications'
@@ -28,3 +30,9 @@ export const [getNotifications, setNotifications] = createGetterSetter(
'FieldFormats'
);
+
+export const [getOverlays, setOverlays] = createGetterSetter('Overlays');
+
+export const [getIndexPatterns, setIndexPatterns] = createGetterSetter(
+ 'IndexPatterns'
+);
diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts
index 282f4ee65dc96..68076cd43c336 100644
--- a/src/plugins/data/public/suggestions_provider/value_suggestions.ts
+++ b/src/plugins/data/public/suggestions_provider/value_suggestions.ts
@@ -28,23 +28,36 @@ export function getSuggestionsProvider(
http: HttpServiceBase
): IGetSuggestions {
const requestSuggestions = memoize(
- (index: string, field: IFieldType, query: string, boolFilter: any = []) => {
+ (
+ index: string,
+ field: IFieldType,
+ query: string,
+ boolFilter: any = [],
+ signal?: AbortSignal
+ ) => {
return http.fetch(`/api/kibana/suggestions/values/${index}`, {
method: 'POST',
body: JSON.stringify({ query, field: field.name, boolFilter }),
+ signal,
});
},
resolver
);
- return async (index: string, field: IFieldType, query: string, boolFilter?: any) => {
+ return async (
+ index: string,
+ field: IFieldType,
+ query: string,
+ boolFilter?: any,
+ signal?: AbortSignal
+ ) => {
const shouldSuggestValues = uiSettings.get('filterEditor:suggestValues');
if (field.type === 'boolean') {
return [true, false];
} else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') {
return [];
}
- return await requestSuggestions(index, field, query, boolFilter);
+ return await requestSuggestions(index, field, query, boolFilter, signal);
};
}
diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts
index 5e1d8797ebf08..202a509ee58c9 100644
--- a/src/plugins/data/public/types.ts
+++ b/src/plugins/data/public/types.ts
@@ -19,32 +19,40 @@
import { CoreStart } from 'src/core/public';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
+import { IUiActionsSetup, IUiActionsStart } from 'src/plugins/ui_actions/public';
import { AutocompletePublicPluginSetup, AutocompletePublicPluginStart } from '.';
import { FieldFormatsSetup, FieldFormatsStart } from './field_formats_provider';
import { ISearchSetup, ISearchStart } from './search';
import { IGetSuggestions } from './suggestions_provider/types';
import { QuerySetup, QueryStart } from './query';
import { IndexPatternSelectProps } from './ui/index_pattern_select';
-import { IndexPatternsStart, IndexPatternsSetup } from './index_patterns';
+import { IndexPatternsContract } from './index_patterns';
+
+export interface DataSetupDependencies {
+ uiActions: IUiActionsSetup;
+}
+
+export interface DataStartDependencies {
+ uiActions: IUiActionsStart;
+}
export interface DataPublicPluginSetup {
autocomplete: AutocompletePublicPluginSetup;
search: ISearchSetup;
fieldFormats: FieldFormatsSetup;
query: QuerySetup;
- indexPatterns?: IndexPatternsSetup;
}
export interface DataPublicPluginStart {
autocomplete: AutocompletePublicPluginStart;
getSuggestions: IGetSuggestions;
+ indexPatterns: IndexPatternsContract;
search: ISearchStart;
fieldFormats: FieldFormatsStart;
query: QueryStart;
ui: {
IndexPatternSelect: React.ComponentType;
};
- indexPatterns: IndexPatternsStart;
}
export * from './autocomplete_provider/types';
diff --git a/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss b/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss
index 84538a62ca005..51204e2a61168 100644
--- a/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss
+++ b/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss
@@ -1,6 +1,3 @@
-@import '@elastic/eui/src/components/form/variables';
-@import '@elastic/eui/src/components/form/mixins';
-
/**
* 1. Allow wrapping of long filter items
*/
diff --git a/src/plugins/data/public/ui/index.ts b/src/plugins/data/public/ui/index.ts
index 9a4bccc21db3e..8bfccd49bdff3 100644
--- a/src/plugins/data/public/ui/index.ts
+++ b/src/plugins/data/public/ui/index.ts
@@ -20,7 +20,6 @@
export { SuggestionsComponent } from './typeahead/suggestions_component';
export { IndexPatternSelect } from './index_pattern_select';
export { FilterBar } from './filter_bar';
-export { applyFiltersPopover } from './apply_filters';
export { QueryStringInput } from './query_string_input/query_string_input';
// temp export - will be removed as final components are migrated to NP
diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap
index 58658b6c839a2..80a5ede567054 100644
--- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap
+++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap
@@ -172,13 +172,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
"register": [MockFunction],
},
"getSuggestions": [MockFunction],
- "indexPatterns": Object {
- "FieldList": Object {},
- "IndexPatternSelect": [MockFunction],
- "flattenHitWrapper": [MockFunction],
- "formatHitProvider": [MockFunction],
- "indexPatterns": [MockFunction],
- },
+ "indexPatterns": Object {},
"query": Object {
"filterManager": [MockFunction],
"savedQueries": [MockFunction],
@@ -305,14 +299,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
},
"http": Object {
"addLoadingCount": [MockFunction],
- "anonymousPaths": AnonymousPaths {
- "basePath": BasePath {
- "basePath": "",
- "get": [Function],
- "prepend": [Function],
- "remove": [Function],
- },
- "paths": Set {},
+ "anonymousPaths": Object {
+ "isAnonymous": [MockFunction],
+ "register": [MockFunction],
},
"basePath": BasePath {
"basePath": "",
@@ -803,13 +792,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
"register": [MockFunction],
},
"getSuggestions": [MockFunction],
- "indexPatterns": Object {
- "FieldList": Object {},
- "IndexPatternSelect": [MockFunction],
- "flattenHitWrapper": [MockFunction],
- "formatHitProvider": [MockFunction],
- "indexPatterns": [MockFunction],
- },
+ "indexPatterns": Object {},
"query": Object {
"filterManager": [MockFunction],
"savedQueries": [MockFunction],
@@ -936,14 +919,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
},
"http": Object {
"addLoadingCount": [MockFunction],
- "anonymousPaths": AnonymousPaths {
- "basePath": BasePath {
- "basePath": "",
- "get": [Function],
- "prepend": [Function],
- "remove": [Function],
- },
- "paths": Set {},
+ "anonymousPaths": Object {
+ "isAnonymous": [MockFunction],
+ "register": [MockFunction],
},
"basePath": BasePath {
"basePath": "",
@@ -1422,13 +1400,7 @@ exports[`QueryStringInput Should pass the query language to the language switche
"register": [MockFunction],
},
"getSuggestions": [MockFunction],
- "indexPatterns": Object {
- "FieldList": Object {},
- "IndexPatternSelect": [MockFunction],
- "flattenHitWrapper": [MockFunction],
- "formatHitProvider": [MockFunction],
- "indexPatterns": [MockFunction],
- },
+ "indexPatterns": Object {},
"query": Object {
"filterManager": [MockFunction],
"savedQueries": [MockFunction],
@@ -1555,14 +1527,9 @@ exports[`QueryStringInput Should pass the query language to the language switche
},
"http": Object {
"addLoadingCount": [MockFunction],
- "anonymousPaths": AnonymousPaths {
- "basePath": BasePath {
- "basePath": "",
- "get": [Function],
- "prepend": [Function],
- "remove": [Function],
- },
- "paths": Set {},
+ "anonymousPaths": Object {
+ "isAnonymous": [MockFunction],
+ "register": [MockFunction],
},
"basePath": BasePath {
"basePath": "",
@@ -2050,13 +2017,7 @@ exports[`QueryStringInput Should pass the query language to the language switche
"register": [MockFunction],
},
"getSuggestions": [MockFunction],
- "indexPatterns": Object {
- "FieldList": Object {},
- "IndexPatternSelect": [MockFunction],
- "flattenHitWrapper": [MockFunction],
- "formatHitProvider": [MockFunction],
- "indexPatterns": [MockFunction],
- },
+ "indexPatterns": Object {},
"query": Object {
"filterManager": [MockFunction],
"savedQueries": [MockFunction],
@@ -2183,14 +2144,9 @@ exports[`QueryStringInput Should pass the query language to the language switche
},
"http": Object {
"addLoadingCount": [MockFunction],
- "anonymousPaths": AnonymousPaths {
- "basePath": BasePath {
- "basePath": "",
- "get": [Function],
- "prepend": [Function],
- "remove": [Function],
- },
- "paths": Set {},
+ "anonymousPaths": Object {
+ "isAnonymous": [MockFunction],
+ "register": [MockFunction],
},
"basePath": BasePath {
"basePath": "",
@@ -2669,13 +2625,7 @@ exports[`QueryStringInput Should render the given query 1`] = `
"register": [MockFunction],
},
"getSuggestions": [MockFunction],
- "indexPatterns": Object {
- "FieldList": Object {},
- "IndexPatternSelect": [MockFunction],
- "flattenHitWrapper": [MockFunction],
- "formatHitProvider": [MockFunction],
- "indexPatterns": [MockFunction],
- },
+ "indexPatterns": Object {},
"query": Object {
"filterManager": [MockFunction],
"savedQueries": [MockFunction],
@@ -2802,14 +2752,9 @@ exports[`QueryStringInput Should render the given query 1`] = `
},
"http": Object {
"addLoadingCount": [MockFunction],
- "anonymousPaths": AnonymousPaths {
- "basePath": BasePath {
- "basePath": "",
- "get": [Function],
- "prepend": [Function],
- "remove": [Function],
- },
- "paths": Set {},
+ "anonymousPaths": Object {
+ "isAnonymous": [MockFunction],
+ "register": [MockFunction],
},
"basePath": BasePath {
"basePath": "",
@@ -3297,13 +3242,7 @@ exports[`QueryStringInput Should render the given query 1`] = `
"register": [MockFunction],
},
"getSuggestions": [MockFunction],
- "indexPatterns": Object {
- "FieldList": Object {},
- "IndexPatternSelect": [MockFunction],
- "flattenHitWrapper": [MockFunction],
- "formatHitProvider": [MockFunction],
- "indexPatterns": [MockFunction],
- },
+ "indexPatterns": Object {},
"query": Object {
"filterManager": [MockFunction],
"savedQueries": [MockFunction],
@@ -3430,14 +3369,9 @@ exports[`QueryStringInput Should render the given query 1`] = `
},
"http": Object {
"addLoadingCount": [MockFunction],
- "anonymousPaths": AnonymousPaths {
- "basePath": BasePath {
- "basePath": "",
- "get": [Function],
- "prepend": [Function],
- "remove": [Function],
- },
- "paths": Set {},
+ "anonymousPaths": Object {
+ "isAnonymous": [MockFunction],
+ "register": [MockFunction],
},
"basePath": BasePath {
"basePath": "",
diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx
index dcc07f4fd43c5..16b22a164f2f0 100644
--- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx
+++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx
@@ -106,6 +106,7 @@ export class QueryStringInputUI extends Component {
public inputRef: HTMLInputElement | null = null;
private persistedLog: PersistedLog | undefined;
+ private abortController: AbortController | undefined;
private services = this.props.kibana.services;
private componentIsUnmounting = false;
@@ -163,12 +164,22 @@ export class QueryStringInputUI extends Component {
return;
}
- const suggestions: AutocompleteSuggestion[] = await getAutocompleteSuggestions({
- query: queryString,
- selectionStart,
- selectionEnd,
- });
- return [...suggestions, ...recentSearchSuggestions];
+ try {
+ if (this.abortController) this.abortController.abort();
+ this.abortController = new AbortController();
+ const suggestions: AutocompleteSuggestion[] = await getAutocompleteSuggestions({
+ query: queryString,
+ selectionStart,
+ selectionEnd,
+ signal: this.abortController.signal,
+ });
+ return [...suggestions, ...recentSearchSuggestions];
+ } catch (e) {
+ // TODO: Waiting on https://github.com/elastic/kibana/issues/51406 for a properly typed error
+ // Ignore aborted requests
+ if (e.message === 'The user aborted a request.') return;
+ throw e;
+ }
};
private getRecentSearchSuggestions = (query: string) => {
diff --git a/src/plugins/data/public/ui/saved_query_management/_saved_query_management_component.scss b/src/plugins/data/public/ui/saved_query_management/_saved_query_management_component.scss
index d43d14945699e..928cb5a34d6de 100644
--- a/src/plugins/data/public/ui/saved_query_management/_saved_query_management_component.scss
+++ b/src/plugins/data/public/ui/saved_query_management/_saved_query_management_component.scss
@@ -1,5 +1,3 @@
-@import '@elastic/eui/src/components/form/variables';
-
.kbnSavedQueryManagement__popover {
max-width: $euiFormMaxWidth;
}
diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js
index 88d2d873521cb..d9a284d34de6b 100644
--- a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js
+++ b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js
@@ -144,6 +144,13 @@ describe('index_patterns/field_capabilities/field_caps_response', () => {
expect(child).toHaveProperty('subType', { nested: { path: 'nested_object_parent' } });
});
+ it('returns nested sub-fields as non-aggregatable', () => {
+ const fields = readFieldCapsResponse(esResponse);
+ // Normally a keyword field would be aggregatable, but the fact that it is nested overrides that
+ const child = fields.find(f => f.name === 'nested_object_parent.child.keyword');
+ expect(child).toHaveProperty('aggregatable', false);
+ });
+
it('handles fields that are both nested and multi', () => {
const fields = readFieldCapsResponse(esResponse);
const child = fields.find(f => f.name === 'nested_object_parent.child.keyword');
diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts
index 06eb30db0b24b..2215bd8a95a1d 100644
--- a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts
+++ b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts
@@ -182,6 +182,14 @@ export function readFieldCapsResponse(fieldCapsResponse: FieldCapsResponse): Fie
if (Object.keys(subType).length > 0) {
field.subType = subType;
+
+ // We don't support aggregating on nested fields, trying to do so in the UI will return
+ // blank results. For now we will stop showing nested fields as an option for aggregation.
+ // Once we add support for nested fields this condition should be removed and old index
+ // patterns should be migrated.
+ if (field.subType.nested) {
+ field.aggregatable = false;
+ }
}
}
});
diff --git a/src/plugins/embeddable/public/lib/containers/container.ts b/src/plugins/embeddable/public/lib/containers/container.ts
index bce16747ed48e..71e7cca3552bb 100644
--- a/src/plugins/embeddable/public/lib/containers/container.ts
+++ b/src/plugins/embeddable/public/lib/containers/container.ts
@@ -240,6 +240,7 @@ export abstract class Container<
...this.input.panels,
[panelState.explicitInput.id]: panelState,
},
+ isEmptyState: false,
} as Partial);
return await this.untilEmbeddableLoaded(panelState.explicitInput.id);
diff --git a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
index 33cb146a056cb..0197582778940 100644
--- a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
+++ b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
@@ -28,7 +28,7 @@ export interface EmbeddableInput {
id: string;
lastReloadRequestTime?: number;
hidePanelTitles?: boolean;
-
+ isEmptyState?: boolean;
/**
* List of action IDs that this embeddable should not render.
*/
diff --git a/src/plugins/inspector/public/views/requests/_requests.scss b/src/plugins/inspector/public/views/requests/_requests.scss
index feaef21fc4810..273c9d0ccba2b 100644
--- a/src/plugins/inspector/public/views/requests/_requests.scss
+++ b/src/plugins/inspector/public/views/requests/_requests.scss
@@ -1,5 +1,3 @@
-@import '@elastic/eui/src/components/button/variables';
-
.insRequestDetailsStats__icon {
margin-right: $euiSizeS;
}
diff --git a/src/plugins/kibana_utils/README.md b/src/plugins/kibana_utils/README.md
index 61ceea2b18385..5501505dbb7e2 100644
--- a/src/plugins/kibana_utils/README.md
+++ b/src/plugins/kibana_utils/README.md
@@ -2,4 +2,4 @@
Utilities for building Kibana plugins.
-- [Store reactive serializable app state in state containers, `createStore`](./docs/store/README.md).
+- [State containers](./docs/state_containers/README.md).
diff --git a/src/legacy/core_plugins/console/public/quarantined/src/__tests__/utils.js b/src/plugins/kibana_utils/demos/demos.test.ts
similarity index 60%
rename from src/legacy/core_plugins/console/public/quarantined/src/__tests__/utils.js
rename to src/plugins/kibana_utils/demos/demos.test.ts
index fa88e42fa557f..4e792ceef117a 100644
--- a/src/legacy/core_plugins/console/public/quarantined/src/__tests__/utils.js
+++ b/src/plugins/kibana_utils/demos/demos.test.ts
@@ -17,20 +17,20 @@
* under the License.
*/
-import expect from '@kbn/expect';
+import { result as counterResult } from './state_containers/counter';
+import { result as todomvcResult } from './state_containers/todomvc';
-import utils from '../utils';
-
-describe('console utils', () => {
- describe('collapseLiteralStrings', () => {
- it('will collapse multiline strings', () => {
- const multiline = '{ "foo": """bar\nbaz""" }';
- expect(utils.collapseLiteralStrings(multiline)).to.be('{ "foo": "bar\\nbaz" }');
+describe('demos', () => {
+ describe('state containers', () => {
+ test('counter demo works', () => {
+ expect(counterResult).toBe(10);
});
- it('will collapse multiline strings with CRLF endings', () => {
- const multiline = '{ "foo": """bar\r\nbaz""" }';
- expect(utils.collapseLiteralStrings(multiline)).to.be('{ "foo": "bar\\r\\nbaz" }');
+ test('TodoMVC demo works', () => {
+ expect(todomvcResult).toEqual([
+ { id: 0, text: 'Learning state containers', completed: true },
+ { id: 1, text: 'Learning transitions...', completed: true },
+ ]);
});
});
});
diff --git a/src/plugins/kibana_utils/demos/state_containers/counter.ts b/src/plugins/kibana_utils/demos/state_containers/counter.ts
new file mode 100644
index 0000000000000..643763cc4cee9
--- /dev/null
+++ b/src/plugins/kibana_utils/demos/state_containers/counter.ts
@@ -0,0 +1,32 @@
+/*
+ * 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 { createStateContainer } from '../../public/state_containers';
+
+const container = createStateContainer(0, {
+ increment: (cnt: number) => (by: number) => cnt + by,
+ double: (cnt: number) => () => cnt * 2,
+});
+
+container.transitions.increment(5);
+container.transitions.double();
+
+console.log(container.get()); // eslint-disable-line
+
+export const result = container.get();
diff --git a/src/plugins/kibana_utils/demos/state_containers/todomvc.ts b/src/plugins/kibana_utils/demos/state_containers/todomvc.ts
new file mode 100644
index 0000000000000..6d0c960e2a5b2
--- /dev/null
+++ b/src/plugins/kibana_utils/demos/state_containers/todomvc.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 { createStateContainer, PureTransition } from '../../public/state_containers';
+
+export interface TodoItem {
+ text: string;
+ completed: boolean;
+ id: number;
+}
+
+export type TodoState = TodoItem[];
+
+export const defaultState: TodoState = [
+ {
+ id: 0,
+ text: 'Learning state containers',
+ completed: false,
+ },
+];
+
+export interface TodoActions {
+ add: PureTransition;
+ edit: PureTransition;
+ delete: PureTransition;
+ complete: PureTransition;
+ completeAll: PureTransition;
+ clearCompleted: PureTransition;
+}
+
+export const pureTransitions: TodoActions = {
+ add: state => todo => [...state, todo],
+ edit: state => todo => state.map(item => (item.id === todo.id ? { ...item, ...todo } : item)),
+ delete: state => id => state.filter(item => item.id !== id),
+ complete: state => id =>
+ state.map(item => (item.id === id ? { ...item, completed: true } : item)),
+ completeAll: state => () => state.map(item => ({ ...item, completed: true })),
+ clearCompleted: state => () => state.filter(({ completed }) => !completed),
+};
+
+const container = createStateContainer(defaultState, pureTransitions);
+
+container.transitions.add({
+ id: 1,
+ text: 'Learning transitions...',
+ completed: false,
+});
+container.transitions.complete(0);
+container.transitions.complete(1);
+
+console.log(container.get()); // eslint-disable-line
+
+export const result = container.get();
diff --git a/src/plugins/kibana_utils/docs/state_containers/README.md b/src/plugins/kibana_utils/docs/state_containers/README.md
new file mode 100644
index 0000000000000..3b7a8b8bd4621
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/README.md
@@ -0,0 +1,50 @@
+# State containers
+
+State containers are Redux-store-like objects meant to help you manage state in
+your services or apps.
+
+- State containers are strongly typed, you will get TypeScript autocompletion suggestions from
+ your editor when accessing state, executing transitions and using React helpers.
+- State containers can be easily hooked up with your React components.
+- State containers can be used without React, too.
+- State containers provide you central place where to store state, instead of spreading
+ state around multiple RxJs observables, which you need to coordinate. With state
+ container you can always access the latest state snapshot synchronously.
+- Unlike Redux, state containers are less verbose, see example below.
+
+
+## Example
+
+```ts
+import { createStateContainer } from 'src/plugins/kibana_utils';
+
+const container = createStateContainer(0, {
+ increment: (cnt: number) => (by: number) => cnt + by,
+ double: (cnt: number) => () => cnt * 2,
+});
+
+container.transitions.increment(5);
+container.transitions.double();
+console.log(container.get()); // 10
+```
+
+
+## Demos
+
+See demos [here](../../demos/state_containers/).
+
+You can run them with
+
+```
+npx -q ts-node src/plugins/kibana_utils/demos/state_containers/counter.ts
+npx -q ts-node src/plugins/kibana_utils/demos/state_containers/todomvc.ts
+```
+
+
+## Reference
+
+- [Creating a state container](./creation.md).
+- [State transitions](./transitions.md).
+- [Using with React](./react.md).
+- [Using without React`](./no_react.md).
+- [Parallels with Redux](./redux.md).
diff --git a/src/plugins/kibana_utils/docs/store/creation.md b/src/plugins/kibana_utils/docs/state_containers/creation.md
similarity index 54%
rename from src/plugins/kibana_utils/docs/store/creation.md
rename to src/plugins/kibana_utils/docs/state_containers/creation.md
index b0184ad45eb84..66d28bbd8603f 100644
--- a/src/plugins/kibana_utils/docs/store/creation.md
+++ b/src/plugins/kibana_utils/docs/state_containers/creation.md
@@ -17,7 +17,7 @@ interface MyState {
}
```
-Create default state of your *store*.
+Create default state of your container.
```ts
const defaultState: MyState = {
@@ -27,17 +27,12 @@ const defaultState: MyState = {
};
```
-Create your state container, i.e *store*.
+Create your a state container.
```ts
-import { createStore } from 'kibana-utils';
+import { createStateContainer } from 'src/plugins/kibana_utils';
-const store = createStore(defaultState);
-console.log(store.get());
-```
+const container = createStateContainer(defaultState, {});
-> ##### N.B.
->
-> State must always be an object `{}`.
->
-> You cannot create a store out of an array, e.g ~~`createStore([])`~~.
+console.log(container.get());
+```
diff --git a/src/plugins/kibana_utils/docs/store/getters.md b/src/plugins/kibana_utils/docs/state_containers/no_react.md
similarity index 83%
rename from src/plugins/kibana_utils/docs/store/getters.md
rename to src/plugins/kibana_utils/docs/state_containers/no_react.md
index 508d0c6ebc18d..7a15483d83b44 100644
--- a/src/plugins/kibana_utils/docs/store/getters.md
+++ b/src/plugins/kibana_utils/docs/state_containers/no_react.md
@@ -1,4 +1,4 @@
-# Reading state
+# Consuming state in non-React setting
To read the current `state` of the store use `.get()` method.
diff --git a/src/plugins/kibana_utils/docs/state_containers/react.md b/src/plugins/kibana_utils/docs/state_containers/react.md
new file mode 100644
index 0000000000000..363fd9253d44f
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react.md
@@ -0,0 +1,41 @@
+# React
+
+`createStateContainerReactHelpers` factory allows you to easily use state containers with React.
+
+
+## Example
+
+
+```ts
+import { createStateContainer, createStateContainerReactHelpers } from 'src/plugins/kibana_utils';
+
+const container = createStateContainer({}, {});
+export const {
+ Provider,
+ Consumer,
+ context,
+ useContainer,
+ useState,
+ useTransitions,
+ useSelector,
+ connect,
+} = createStateContainerReactHelpers();
+```
+
+Wrap your app with ``.
+
+```tsx
+
+
+
+```
+
+
+## Reference
+
+- [`useContainer()`](./react/use_container.md)
+- [`useState()`](./react/use_state.md)
+- [`useSelector()`](./react/use_selector.md)
+- [`useTransitions()`](./react/use_transitions.md)
+- [`connect()()`](./react/connect.md)
+- [Context](./react/context.md)
diff --git a/src/plugins/kibana_utils/docs/state_containers/react/connect.md b/src/plugins/kibana_utils/docs/state_containers/react/connect.md
new file mode 100644
index 0000000000000..56b7e0fbc5673
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react/connect.md
@@ -0,0 +1,22 @@
+# `connect()()` higher order component
+
+Use `connect()()` higher-order-component to inject props from state into your component.
+
+```tsx
+interface Props {
+ name: string;
+ punctuation: '.' | ',' | '!',
+}
+const Demo: React.FC = ({ name, punctuation }) =>
+ Hello, {name}{punctuation}
;
+
+const store = createStateContainer({ userName: 'John' });
+const { Provider, connect } = createStateContainerReactHelpers(store);
+
+const mapStateToProps = ({ userName }) => ({ name: userName });
+const DemoConnected = connect(mapStateToProps)(Demo);
+
+
+
+
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/react/context.md b/src/plugins/kibana_utils/docs/state_containers/react/context.md
new file mode 100644
index 0000000000000..33f084fdfe9d7
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react/context.md
@@ -0,0 +1,24 @@
+# React context
+
+`createStateContainerReactHelpers` returns `` and `` components
+as well as `context` React context object.
+
+```ts
+export const {
+ Provider,
+ Consumer,
+ context,
+} = createStateContainerReactHelpers();
+```
+
+`` and `` are just regular React context components.
+
+```tsx
+
+
+
{container =>
+ {JSON.stringify(container.get())}
+ }
+
+
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/react/use_container.md b/src/plugins/kibana_utils/docs/state_containers/react/use_container.md
new file mode 100644
index 0000000000000..5e698edb8529c
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react/use_container.md
@@ -0,0 +1,10 @@
+# `useContainer` hook
+
+`useContainer` React hook will simply return you `container` object from React context.
+
+```tsx
+const Demo = () => {
+ const store = useContainer();
+ return {store.get().isDarkMode ? '🌑' : '☀️'}
;
+};
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/react/use_selector.md b/src/plugins/kibana_utils/docs/state_containers/react/use_selector.md
new file mode 100644
index 0000000000000..2ecf772fba367
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react/use_selector.md
@@ -0,0 +1,20 @@
+# `useSelector()` hook
+
+With `useSelector` React hook you specify a selector function, which will pick specific
+data from the state. *Your component will update only when that specific part of the state changes.*
+
+```tsx
+const selector = state => state.isDarkMode;
+const Demo = () => {
+ const isDarkMode = useSelector(selector);
+ return {isDarkMode ? '🌑' : '☀️'}
;
+};
+```
+
+As an optional second argument for `useSelector` you can provide a `comparator` function, which
+compares currently selected value with the previous and your component will re-render only if
+`comparator` returns `true`. By default it uses [`fast-deep-equal`](https://github.com/epoberezkin/fast-deep-equal).
+
+```
+useSelector(selector, comparator?)
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/react/use_state.md b/src/plugins/kibana_utils/docs/state_containers/react/use_state.md
new file mode 100644
index 0000000000000..5db1d46897aad
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react/use_state.md
@@ -0,0 +1,11 @@
+# `useState()` hook
+
+- `useState` hook returns you directly the state of the container.
+- It also forces component to re-render every time state changes.
+
+```tsx
+const Demo = () => {
+ const { isDarkMode } = useState();
+ return {isDarkMode ? '🌑' : '☀️'}
;
+};
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/react/use_transitions.md b/src/plugins/kibana_utils/docs/state_containers/react/use_transitions.md
new file mode 100644
index 0000000000000..c6783bf0e0f0a
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/react/use_transitions.md
@@ -0,0 +1,17 @@
+# `useTransitions` hook
+
+Access [state transitions](../transitions.md) by `useTransitions` React hook.
+
+```tsx
+const Demo = () => {
+ const { isDarkMode } = useState();
+ const { setDarkMode } = useTransitions();
+ return (
+ <>
+ {isDarkMode ? '🌑' : '☀️'}
+ setDarkMode(true)}>Go dark
+ setDarkMode(false)}>Go light
+ >
+ );
+};
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/redux.md b/src/plugins/kibana_utils/docs/state_containers/redux.md
new file mode 100644
index 0000000000000..1a60d841a8b75
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/redux.md
@@ -0,0 +1,40 @@
+# Redux
+
+State containers similar to Redux stores but without the boilerplate.
+
+State containers expose Redux-like API:
+
+```js
+container.getState()
+container.dispatch()
+container.replaceReducer()
+container.subscribe()
+container.addMiddleware()
+```
+
+State containers have a reducer and every time you execute a state transition it
+actually dispatches an "action". For example, this
+
+```js
+container.transitions.increment(25);
+```
+
+is equivalent to
+
+```js
+container.dispatch({
+ type: 'increment',
+ args: [25],
+});
+```
+
+Because all transitions happen through `.dispatch()` interface, you can add middleware—similar how you
+would do with Redux—to monitor or intercept transitions.
+
+For example, you can add `redux-logger` middleware to log in console all transitions happening with your store.
+
+```js
+import logger from 'redux-logger';
+
+container.addMiddleware(logger);
+```
diff --git a/src/plugins/kibana_utils/docs/state_containers/transitions.md b/src/plugins/kibana_utils/docs/state_containers/transitions.md
new file mode 100644
index 0000000000000..51d52cdf3daaf
--- /dev/null
+++ b/src/plugins/kibana_utils/docs/state_containers/transitions.md
@@ -0,0 +1,61 @@
+# State transitions
+
+*State transitions* describe possible state changes over time. Transitions are pure functions which
+receive `state` object and other—optional—arguments and must return a new `state` object back.
+
+```ts
+type Transition = (state: State) => (...args) => State;
+```
+
+Transitions must not mutate `state` object in-place, instead they must return a
+shallow copy of it, e.g. `{ ...state }`. Example:
+
+```ts
+const setUiMode: PureTransition = state => uiMode => ({ ...state, uiMode });
+```
+
+You provide transitions as a second argument when you create your state container.
+
+```ts
+import { createStateContainer } from 'src/plugins/kibana_utils';
+
+const container = createStateContainer(0, {
+ increment: (cnt: number) => (by: number) => cnt + by,
+ double: (cnt: number) => () => cnt * 2,
+});
+```
+
+Now you can execute the transitions by calling them with only optional parameters (`state` is
+provided to your transitions automatically).
+
+```ts
+container.transitions.increment(25);
+container.transitions.increment(5);
+container.state; // 30
+```
+
+Your transitions are bound to the container so you can treat each of them as a
+standalone function for export.
+
+```ts
+const defaultState = {
+ uiMode: 'light',
+};
+
+const container = createStateContainer(defaultState, {
+ setUiMode: state => uiMode => ({ ...state, uiMode }),
+ resetUiMode: state => () => ({ ...state, uiMode: defaultState.uiMode }),
+});
+
+export const {
+ setUiMode,
+ resetUiMode
+} = container.transitions;
+```
+
+You can add TypeScript annotations for your transitions as the second generic argument
+to `createStateContainer()` function.
+
+```ts
+const container = createStateContainer(defaultState, pureTransitions);
+```
diff --git a/src/plugins/kibana_utils/docs/store/README.md b/src/plugins/kibana_utils/docs/store/README.md
deleted file mode 100644
index e1cb098fe04ce..0000000000000
--- a/src/plugins/kibana_utils/docs/store/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# State containers
-
-- State containers for holding serializable state.
-- [Each plugin/app that needs runtime state will create a *store* using `store = createStore()`](./creation.md).
-- [*Store* can be updated using mutators `mutators = store.createMutators({ ... })`](./mutators.md).
-- [*Store* can be connected to React `{Provider, connect} = createContext(store)`](./react.md).
-- [In no-React setting *store* is consumed using `store.get()` and `store.state$`](./getters.md).
-- [Under-the-hood uses Redux `store.redux`](./redux.md) (but you should never need it explicitly).
-- [See idea doc with samples and rationale](https://docs.google.com/document/d/18eitHkcyKSsEHUfUIqFKChc8Pp62Z4gcRxdu903hbA0/edit#heading=h.iaxc9whxifl5).
diff --git a/src/plugins/kibana_utils/docs/store/mutators.md b/src/plugins/kibana_utils/docs/store/mutators.md
deleted file mode 100644
index 9db1b1bb60b3c..0000000000000
--- a/src/plugins/kibana_utils/docs/store/mutators.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# Mutators
-
-State *mutators* are pure functions which receive `state` object and other—optional—arguments
-and must return a new `state` object back.
-
-```ts
-type Mutator = (state: State) => (...args) => State;
-```
-
-Mutator must not mutate `state` object in-place, instead it should return a
-shallow copy of it, e.g. `{ ...state }`.
-
-```ts
-const setUiMode: Mutator = state => uiMode => ({ ...state, uiMode });
-```
-
-You create mutators using `.createMutator(...)` method.
-
-```ts
-const store = createStore({uiMode: 'light'});
-const mutators = store.createMutators({
- setUiMode: state => uiMode => ({ ...state, uiMode }),
-});
-```
-
-Now you can use your mutators by calling them with only optional parameters (`state` is
-provided to your mutator automatically).
-
-```ts
-mutators.setUiMode('dark');
-```
-
-Your mutators are bound to the `store` so you can treat each of them as a
-standalone function for export.
-
-```ts
-const { setUiMode, resetUiMode } = store.createMutators({
- setUiMode: state => uiMode => ({ ...state, uiMode }),
- resetUiMode: state => () => ({ ...state, uiMode: 'light' }),
-});
-
-export {
- setUiMode,
- resetUiMode,
-};
-```
-
-The mutators you create are also available on the `store` object.
-
-```ts
-const store = createStore({ cnt: 0 });
-store.createMutators({
- add: state => value => ({ ...state, cnt: state.cnt + value }),
-});
-
-store.mutators.add(5);
-store.get(); // { cnt: 5 }
-```
-
-You can add TypeScript annotations to your `.mutators` property of `store` object.
-
-```ts
-const store = createStore<{
- cnt: number;
-}, {
- add: (value: number) => void;
-}>({
- cnt: 0
-});
-```
diff --git a/src/plugins/kibana_utils/docs/store/react.md b/src/plugins/kibana_utils/docs/store/react.md
deleted file mode 100644
index 68a016ed6d3ca..0000000000000
--- a/src/plugins/kibana_utils/docs/store/react.md
+++ /dev/null
@@ -1,101 +0,0 @@
-# React
-
-`createContext` factory allows you to easily use state containers with React.
-
-```ts
-import { createStore, createContext } from 'kibana-utils';
-
-const store = createStore({});
-const {
- Provider,
- Consumer,
- connect,
- context,
- useStore,
- useState,
- useMutators,
- useSelector,
-} = createContext(store);
-```
-
-Wrap your app with ``.
-
-```tsx
-
-
-
-```
-
-Use `connect()()` higer-order-component to inject props from state into your component.
-
-```tsx
-interface Props {
- name: string;
- punctuation: '.' | ',' | '!',
-}
-const Demo: React.FC = ({ name, punctuation }) =>
- Hello, {name}{punctuation}
;
-
-const store = createStore({ userName: 'John' });
-const { Provider, connect } = createContext(store);
-
-const mapStateToProps = ({ userName }) => ({ name: userName });
-const DemoConnected = connect(mapStateToProps)(Demo);
-
-
-
-
-```
-
-`useStore` React hook will fetch the `store` object from the context.
-
-```tsx
-const Demo = () => {
- const store = useStore();
- return {store.get().isDarkMode ? '🌑' : '☀️'}
;
-};
-```
-
-If you want your component to always re-render when the state changes use `useState` React hook.
-
-```tsx
-const Demo = () => {
- const { isDarkMode } = useState();
- return {isDarkMode ? '🌑' : '☀️'}
;
-};
-```
-
-For `useSelector` React hook you specify a selector function, which will pick specific
-data from the state. *Your component will update only when that specific part of the state changes.*
-
-```tsx
-const selector = state => state.isDarkMode;
-const Demo = () => {
- const isDarkMode = useSelector(selector);
- return {isDarkMode ? '🌑' : '☀️'}
;
-};
-```
-
-As an optional second argument for `useSelector` you can provide a `comparator` function, which
-compares currently selected value with the previous and your component will re-render only if
-`comparator` returns `true`. By default, it simply uses tripple equals `===` comparison.
-
-```
-useSelector(selector, comparator?)
-```
-
-Access state mutators by `useMutators` React hook.
-
-```tsx
-const Demo = () => {
- const { isDarkMode } = useState();
- const { setDarkMode } = useMutators();
- return (
- <>
- {isDarkMode ? '🌑' : '☀️'}
- setDarkMode(true)}>Go dark
- setDarkMode(false)}>Go light
- >
- );
-};
-```
diff --git a/src/plugins/kibana_utils/docs/store/redux.md b/src/plugins/kibana_utils/docs/store/redux.md
deleted file mode 100644
index 23be76f35b36e..0000000000000
--- a/src/plugins/kibana_utils/docs/store/redux.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Redux
-
-Internally `createStore()` uses Redux to manage the state. When you call `store.get()`
-it is actually calling the Redux `.getState()` method. When you execute a mutation
-it is actually dispatching a Redux action.
-
-You can access Redux *store* using `.redux`.
-
-```ts
-store.redux;
-```
-
-But you should never need it, if you think you do, consult with Kibana App Architecture team.
-
-We use Redux internally for 3 main reasons:
-
-- We can reuse `react-redux` library to easily connect state containers to React.
-- We can reuse Redux devtools.
-- We can reuse battle-tested Redux library and action/reducer paradigm.
diff --git a/src/plugins/kibana_utils/public/index.test.ts b/src/plugins/kibana_utils/public/index.test.ts
index 0e2a4acf15f04..27c4d6c1c06e9 100644
--- a/src/plugins/kibana_utils/public/index.test.ts
+++ b/src/plugins/kibana_utils/public/index.test.ts
@@ -17,9 +17,9 @@
* under the License.
*/
-import { createStore, createContext } from '.';
+import { createStateContainer, createStateContainerReactHelpers } from '.';
test('exports store methods', () => {
- expect(typeof createStore).toBe('function');
- expect(typeof createContext).toBe('function');
+ expect(typeof createStateContainer).toBe('function');
+ expect(typeof createStateContainerReactHelpers).toBe('function');
});
diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts
index 22ac720246d4b..3f5aeebac54d8 100644
--- a/src/plugins/kibana_utils/public/index.ts
+++ b/src/plugins/kibana_utils/public/index.ts
@@ -19,12 +19,13 @@
export * from './core';
export * from './errors';
-export * from './store';
-export * from './parse';
-export * from './resize_checker';
-export * from './render_complete';
-export * from './store';
export * from './errors';
export * from './field_mapping';
+export * from './parse';
+export * from './render_complete';
+export * from './resize_checker';
+export * from './state_containers';
export * from './storage';
export * from './storage/hashed_item_store';
+export * from './state_management/state_hash';
+export * from './state_management/url';
diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container.test.ts b/src/plugins/kibana_utils/public/state_containers/create_state_container.test.ts
new file mode 100644
index 0000000000000..9165181299a90
--- /dev/null
+++ b/src/plugins/kibana_utils/public/state_containers/create_state_container.test.ts
@@ -0,0 +1,303 @@
+/*
+ * 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 { createStateContainer } from './create_state_container';
+
+const create = (state: S, transitions: T = {} as T) => {
+ const pureTransitions = {
+ set: () => (newState: S) => newState,
+ ...transitions,
+ };
+ const store = createStateContainer(state, pureTransitions);
+ return { store, mutators: store.transitions };
+};
+
+test('can create store', () => {
+ const { store } = create({});
+ expect(store).toMatchObject({
+ getState: expect.any(Function),
+ state$: expect.any(Object),
+ transitions: expect.any(Object),
+ dispatch: expect.any(Function),
+ subscribe: expect.any(Function),
+ replaceReducer: expect.any(Function),
+ addMiddleware: expect.any(Function),
+ });
+});
+
+test('can set default state', () => {
+ const defaultState = {
+ foo: 'bar',
+ };
+ const { store } = create(defaultState);
+ expect(store.get()).toEqual(defaultState);
+ expect(store.getState()).toEqual(defaultState);
+});
+
+test('can set state', () => {
+ const defaultState = {
+ foo: 'bar',
+ };
+ const newState = {
+ foo: 'baz',
+ };
+ const { store, mutators } = create(defaultState);
+
+ mutators.set(newState);
+
+ expect(store.get()).toEqual(newState);
+ expect(store.getState()).toEqual(newState);
+});
+
+test('does not shallow merge states', () => {
+ const defaultState = {
+ foo: 'bar',
+ };
+ const newState = {
+ foo2: 'baz',
+ };
+ const { store, mutators } = create(defaultState);
+
+ mutators.set(newState as any);
+
+ expect(store.get()).toEqual(newState);
+ expect(store.getState()).toEqual(newState);
+});
+
+test('can subscribe and unsubscribe to state changes', () => {
+ const { store, mutators } = create({});
+ const spy = jest.fn();
+ const subscription = store.state$.subscribe(spy);
+ mutators.set({ a: 1 });
+ mutators.set({ a: 2 });
+ subscription.unsubscribe();
+ mutators.set({ a: 3 });
+
+ expect(spy).toHaveBeenCalledTimes(2);
+ expect(spy.mock.calls[0][0]).toEqual({ a: 1 });
+ expect(spy.mock.calls[1][0]).toEqual({ a: 2 });
+});
+
+test('multiple subscribers can subscribe', () => {
+ const { store, mutators } = create({});
+ const spy1 = jest.fn();
+ const spy2 = jest.fn();
+ const subscription1 = store.state$.subscribe(spy1);
+ const subscription2 = store.state$.subscribe(spy2);
+ mutators.set({ a: 1 });
+ subscription1.unsubscribe();
+ mutators.set({ a: 2 });
+ subscription2.unsubscribe();
+ mutators.set({ a: 3 });
+
+ expect(spy1).toHaveBeenCalledTimes(1);
+ expect(spy2).toHaveBeenCalledTimes(2);
+ expect(spy1.mock.calls[0][0]).toEqual({ a: 1 });
+ expect(spy2.mock.calls[0][0]).toEqual({ a: 1 });
+ expect(spy2.mock.calls[1][0]).toEqual({ a: 2 });
+});
+
+test('creates impure mutators from pure mutators', () => {
+ const { mutators } = create(
+ {},
+ {
+ setFoo: () => (bar: any) => ({ foo: bar }),
+ }
+ );
+
+ expect(typeof mutators.setFoo).toBe('function');
+});
+
+test('mutators can update state', () => {
+ const { store, mutators } = create(
+ {
+ value: 0,
+ foo: 'bar',
+ },
+ {
+ add: (state: any) => (increment: any) => ({ ...state, value: state.value + increment }),
+ setFoo: (state: any) => (bar: any) => ({ ...state, foo: bar }),
+ }
+ );
+
+ expect(store.get()).toEqual({
+ value: 0,
+ foo: 'bar',
+ });
+
+ mutators.add(11);
+ mutators.setFoo('baz');
+
+ expect(store.get()).toEqual({
+ value: 11,
+ foo: 'baz',
+ });
+
+ mutators.add(-20);
+ mutators.setFoo('bazooka');
+
+ expect(store.get()).toEqual({
+ value: -9,
+ foo: 'bazooka',
+ });
+});
+
+test('mutators methods are not bound', () => {
+ const { store, mutators } = create(
+ { value: -3 },
+ {
+ add: (state: { value: number }) => (increment: number) => ({
+ ...state,
+ value: state.value + increment,
+ }),
+ }
+ );
+
+ expect(store.get()).toEqual({ value: -3 });
+ mutators.add(4);
+ expect(store.get()).toEqual({ value: 1 });
+});
+
+test('created mutators are saved in store object', () => {
+ const { store, mutators } = create(
+ { value: -3 },
+ {
+ add: (state: { value: number }) => (increment: number) => ({
+ ...state,
+ value: state.value + increment,
+ }),
+ }
+ );
+
+ expect(typeof store.transitions.add).toBe('function');
+ mutators.add(5);
+ expect(store.get()).toEqual({ value: 2 });
+});
+
+test('throws when state is modified inline - 1', () => {
+ const container = createStateContainer({ a: 'b' }, {});
+
+ let error: TypeError | null = null;
+ try {
+ (container.get().a as any) = 'c';
+ } catch (err) {
+ error = err;
+ }
+
+ expect(error).toBeInstanceOf(TypeError);
+});
+
+test('throws when state is modified inline - 2', () => {
+ const container = createStateContainer({ a: 'b' }, {});
+
+ let error: TypeError | null = null;
+ try {
+ (container.getState().a as any) = 'c';
+ } catch (err) {
+ error = err;
+ }
+
+ expect(error).toBeInstanceOf(TypeError);
+});
+
+test('throws when state is modified inline in subscription', done => {
+ const container = createStateContainer({ a: 'b' }, { set: () => (newState: any) => newState });
+
+ container.subscribe(value => {
+ let error: TypeError | null = null;
+ try {
+ (value.a as any) = 'd';
+ } catch (err) {
+ error = err;
+ }
+ expect(error).toBeInstanceOf(TypeError);
+ done();
+ });
+ container.transitions.set({ a: 'c' });
+});
+
+describe('selectors', () => {
+ test('can specify no selectors, or can skip them', () => {
+ createStateContainer({}, {});
+ createStateContainer({}, {}, {});
+ });
+
+ test('selector object is available on .selectors key', () => {
+ const container1 = createStateContainer({}, {}, {});
+ const container2 = createStateContainer({}, {}, { foo: () => () => 123 });
+ const container3 = createStateContainer({}, {}, { bar: () => () => 1, baz: () => () => 1 });
+
+ expect(Object.keys(container1.selectors).sort()).toEqual([]);
+ expect(Object.keys(container2.selectors).sort()).toEqual(['foo']);
+ expect(Object.keys(container3.selectors).sort()).toEqual(['bar', 'baz']);
+ });
+
+ test('selector without arguments returns correct state slice', () => {
+ const container = createStateContainer(
+ { name: 'Oleg' },
+ {
+ changeName: (state: { name: string }) => (name: string) => ({ ...state, name }),
+ },
+ { getName: (state: { name: string }) => () => state.name }
+ );
+
+ expect(container.selectors.getName()).toBe('Oleg');
+ container.transitions.changeName('Britney');
+ expect(container.selectors.getName()).toBe('Britney');
+ });
+
+ test('selector can accept an argument', () => {
+ const container = createStateContainer(
+ {
+ users: {
+ 1: {
+ name: 'Darth',
+ },
+ },
+ },
+ {},
+ {
+ getUser: (state: any) => (id: number) => state.users[id],
+ }
+ );
+
+ expect(container.selectors.getUser(1)).toEqual({ name: 'Darth' });
+ expect(container.selectors.getUser(2)).toBe(undefined);
+ });
+
+ test('selector can accept multiple arguments', () => {
+ const container = createStateContainer(
+ {
+ users: {
+ 5: {
+ name: 'Darth',
+ surname: 'Vader',
+ },
+ },
+ },
+ {},
+ {
+ getName: (state: any) => (id: number, which: 'name' | 'surname') => state.users[id][which],
+ }
+ );
+
+ expect(container.selectors.getName(5, 'name')).toEqual('Darth');
+ expect(container.selectors.getName(5, 'surname')).toEqual('Vader');
+ });
+});
diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container.ts b/src/plugins/kibana_utils/public/state_containers/create_state_container.ts
new file mode 100644
index 0000000000000..1ef4a1c012817
--- /dev/null
+++ b/src/plugins/kibana_utils/public/state_containers/create_state_container.ts
@@ -0,0 +1,89 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { BehaviorSubject } from 'rxjs';
+import { skip } from 'rxjs/operators';
+import { RecursiveReadonly } from '@kbn/utility-types';
+import {
+ PureTransitionsToTransitions,
+ PureTransition,
+ ReduxLikeStateContainer,
+ PureSelectorsToSelectors,
+} from './types';
+
+const $$observable = (typeof Symbol === 'function' && (Symbol as any).observable) || '@@observable';
+
+const freeze: (value: T) => RecursiveReadonly =
+ process.env.NODE_ENV !== 'production'
+ ? (value: T): RecursiveReadonly => {
+ if (!value) return value as RecursiveReadonly;
+ if (value instanceof Array) return value as RecursiveReadonly;
+ if (typeof value === 'object') return Object.freeze({ ...value }) as RecursiveReadonly;
+ else return value as RecursiveReadonly;
+ }
+ : (value: T) => value as RecursiveReadonly;
+
+export const createStateContainer = <
+ State,
+ PureTransitions extends object,
+ PureSelectors extends object = {}
+>(
+ defaultState: State,
+ pureTransitions: PureTransitions,
+ pureSelectors: PureSelectors = {} as PureSelectors
+): ReduxLikeStateContainer => {
+ const data$ = new BehaviorSubject>(freeze(defaultState));
+ const state$ = data$.pipe(skip(1));
+ const get = () => data$.getValue();
+ const container: ReduxLikeStateContainer = {
+ get,
+ state$,
+ getState: () => data$.getValue(),
+ set: (state: State) => {
+ data$.next(freeze(state));
+ },
+ reducer: (state, action) => {
+ const pureTransition = (pureTransitions as Record>)[
+ action.type
+ ];
+ return pureTransition ? freeze(pureTransition(state)(...action.args)) : state;
+ },
+ replaceReducer: nextReducer => (container.reducer = nextReducer),
+ dispatch: action => data$.next(container.reducer(get(), action)),
+ transitions: Object.keys(pureTransitions).reduce>(
+ (acc, type) => ({ ...acc, [type]: (...args: any) => container.dispatch({ type, args }) }),
+ {} as PureTransitionsToTransitions
+ ),
+ selectors: Object.keys(pureSelectors).reduce>(
+ (acc, selector) => ({
+ ...acc,
+ [selector]: (...args: any) => (pureSelectors as any)[selector](get())(...args),
+ }),
+ {} as PureSelectorsToSelectors
+ ),
+ addMiddleware: middleware =>
+ (container.dispatch = middleware(container as any)(container.dispatch)),
+ subscribe: (listener: (state: RecursiveReadonly) => void) => {
+ const subscription = state$.subscribe(listener);
+ return () => subscription.unsubscribe();
+ },
+ [$$observable]: state$,
+ };
+ return container;
+};
diff --git a/src/plugins/kibana_utils/public/store/react.test.tsx b/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.test.tsx
similarity index 65%
rename from src/plugins/kibana_utils/public/store/react.test.tsx
rename to src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.test.tsx
index e629e9d0e1257..8f5810f3e147d 100644
--- a/src/plugins/kibana_utils/public/store/react.test.tsx
+++ b/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.test.tsx
@@ -20,8 +20,17 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { act, Simulate } from 'react-dom/test-utils';
-import { createStore } from './create_store';
-import { createContext } from './react';
+import { createStateContainer } from './create_state_container';
+import { createStateContainerReactHelpers } from './create_state_container_react_helpers';
+
+const create = (state: S, transitions: T = {} as T) => {
+ const pureTransitions = {
+ set: () => (newState: S) => newState,
+ ...transitions,
+ };
+ const store = createStateContainer(state, pureTransitions);
+ return { store, mutators: store.transitions };
+};
let container: HTMLDivElement | null;
@@ -36,27 +45,23 @@ afterEach(() => {
});
test('can create React context', () => {
- const store = createStore({ foo: 'bar' });
- const context = createContext(store);
+ const context = createStateContainerReactHelpers();
expect(context).toMatchObject({
- Provider: expect.any(Function),
- Consumer: expect.any(Function),
+ Provider: expect.any(Object),
+ Consumer: expect.any(Object),
connect: expect.any(Function),
- context: {
- Provider: expect.any(Object),
- Consumer: expect.any(Object),
- },
+ context: expect.any(Object),
});
});
test(' passes state to ', () => {
- const store = createStore({ hello: 'world' });
- const { Provider, Consumer } = createContext(store);
+ const { store } = create({ hello: 'world' });
+ const { Provider, Consumer } = createStateContainerReactHelpers();
ReactDOM.render(
-
- {({ hello }) => hello}
+
+ {(s: typeof store) => s.get().hello}
,
container
);
@@ -74,8 +79,8 @@ interface Props1 {
}
test(' passes state to connect()()', () => {
- const store = createStore({ hello: 'Bob' });
- const { Provider, connect } = createContext(store);
+ const { store } = create({ hello: 'Bob' });
+ const { Provider, connect } = createStateContainerReactHelpers();
const Demo: React.FC = ({ message, stop }) => (
<>
@@ -87,7 +92,7 @@ test(' passes state to connect()()', () => {
const DemoConnected = connect(mergeProps)(Demo);
ReactDOM.render(
-
+
,
container
@@ -97,13 +102,13 @@ test(' passes state to connect()()', () => {
});
test('context receives Redux store', () => {
- const store = createStore({ foo: 'bar' });
- const { Provider, context } = createContext(store);
+ const { store } = create({ foo: 'bar' });
+ const { Provider, context } = createStateContainerReactHelpers();
ReactDOM.render(
/* eslint-disable no-shadow */
-
- {({ store }) => store.getState().foo}
+
+ {store => store.get().foo}
,
/* eslint-enable no-shadow */
container
@@ -117,16 +122,16 @@ xtest('can use multiple stores in one React app', () => {});
describe('hooks', () => {
describe('useStore', () => {
test('can select store using useStore hook', () => {
- const store = createStore({ foo: 'bar' });
- const { Provider, useStore } = createContext(store);
+ const { store } = create({ foo: 'bar' });
+ const { Provider, useContainer } = createStateContainerReactHelpers();
const Demo: React.FC<{}> = () => {
// eslint-disable-next-line no-shadow
- const store = useStore();
+ const store = useContainer();
return <>{store.get().foo}>;
};
ReactDOM.render(
-
+
,
container
@@ -138,15 +143,15 @@ describe('hooks', () => {
describe('useState', () => {
test('can select state using useState hook', () => {
- const store = createStore({ foo: 'qux' });
- const { Provider, useState } = createContext(store);
+ const { store } = create({ foo: 'qux' });
+ const { Provider, useState } = createStateContainerReactHelpers();
const Demo: React.FC<{}> = () => {
const { foo } = useState();
return <>{foo}>;
};
ReactDOM.render(
-
+
,
container
@@ -156,18 +161,23 @@ describe('hooks', () => {
});
test('re-renders when state changes', () => {
- const store = createStore({ foo: 'bar' });
- const { setFoo } = store.createMutators({
- setFoo: state => foo => ({ ...state, foo }),
- });
- const { Provider, useState } = createContext(store);
+ const {
+ store,
+ mutators: { setFoo },
+ } = create(
+ { foo: 'bar' },
+ {
+ setFoo: (state: { foo: string }) => (foo: string) => ({ ...state, foo }),
+ }
+ );
+ const { Provider, useState } = createStateContainerReactHelpers();
const Demo: React.FC<{}> = () => {
const { foo } = useState();
return <>{foo}>;
};
ReactDOM.render(
-
+
,
container
@@ -181,26 +191,31 @@ describe('hooks', () => {
});
});
- describe('useMutations', () => {
- test('useMutations hook returns mutations that can update state', () => {
- const store = createStore<
+ describe('useTransitions', () => {
+ test('useTransitions hook returns mutations that can update state', () => {
+ const { store } = create<
{
cnt: number;
},
+ any
+ >(
{
- increment: (value: number) => void;
+ cnt: 0,
+ },
+ {
+ increment: (state: { cnt: number }) => (value: number) => ({
+ ...state,
+ cnt: state.cnt + value,
+ }),
}
- >({
- cnt: 0,
- });
- store.createMutators({
- increment: state => value => ({ ...state, cnt: state.cnt + value }),
- });
+ );
- const { Provider, useState, useMutators } = createContext(store);
+ const { Provider, useState, useTransitions } = createStateContainerReactHelpers<
+ typeof store
+ >();
const Demo: React.FC<{}> = () => {
const { cnt } = useState();
- const { increment } = useMutators();
+ const { increment } = useTransitions();
return (
<>
{cnt}
@@ -210,7 +225,7 @@ describe('hooks', () => {
};
ReactDOM.render(
-
+
,
container
@@ -230,7 +245,7 @@ describe('hooks', () => {
describe('useSelector', () => {
test('can select deeply nested value', () => {
- const store = createStore({
+ const { store } = create({
foo: {
bar: {
baz: 'qux',
@@ -238,14 +253,14 @@ describe('hooks', () => {
},
});
const selector = (state: { foo: { bar: { baz: string } } }) => state.foo.bar.baz;
- const { Provider, useSelector } = createContext(store);
+ const { Provider, useSelector } = createStateContainerReactHelpers();
const Demo: React.FC<{}> = () => {
const value = useSelector(selector);
return <>{value}>;
};
ReactDOM.render(
-
+
,
container
@@ -255,7 +270,7 @@ describe('hooks', () => {
});
test('re-renders when state changes', () => {
- const store = createStore({
+ const { store, mutators } = create({
foo: {
bar: {
baz: 'qux',
@@ -263,14 +278,14 @@ describe('hooks', () => {
},
});
const selector = (state: { foo: { bar: { baz: string } } }) => state.foo.bar.baz;
- const { Provider, useSelector } = createContext(store);
+ const { Provider, useSelector } = createStateContainerReactHelpers();
const Demo: React.FC<{}> = () => {
const value = useSelector(selector);
return <>{value}>;
};
ReactDOM.render(
-
+
,
container
@@ -278,7 +293,7 @@ describe('hooks', () => {
expect(container!.innerHTML).toBe('qux');
act(() => {
- store.set({
+ mutators.set({
foo: {
bar: {
baz: 'quux',
@@ -290,9 +305,9 @@ describe('hooks', () => {
});
test("re-renders only when selector's result changes", async () => {
- const store = createStore({ a: 'b', foo: 'bar' });
+ const { store, mutators } = create({ a: 'b', foo: 'bar' });
const selector = (state: { foo: string }) => state.foo;
- const { Provider, useSelector } = createContext(store);
+ const { Provider, useSelector } = createStateContainerReactHelpers();
let cnt = 0;
const Demo: React.FC<{}> = () => {
@@ -301,7 +316,7 @@ describe('hooks', () => {
return <>{value}>;
};
ReactDOM.render(
-
+
,
container
@@ -311,24 +326,24 @@ describe('hooks', () => {
expect(cnt).toBe(1);
act(() => {
- store.set({ a: 'c', foo: 'bar' });
+ mutators.set({ a: 'c', foo: 'bar' });
});
await new Promise(r => setTimeout(r, 1));
expect(cnt).toBe(1);
act(() => {
- store.set({ a: 'd', foo: 'bar 2' });
+ mutators.set({ a: 'd', foo: 'bar 2' });
});
await new Promise(r => setTimeout(r, 1));
expect(cnt).toBe(2);
});
- test('re-renders on same shape object', async () => {
- const store = createStore({ foo: { bar: 'baz' } });
+ test('does not re-render on same shape object', async () => {
+ const { store, mutators } = create({ foo: { bar: 'baz' } });
const selector = (state: { foo: any }) => state.foo;
- const { Provider, useSelector } = createContext(store);
+ const { Provider, useSelector } = createStateContainerReactHelpers();
let cnt = 0;
const Demo: React.FC<{}> = () => {
@@ -337,7 +352,7 @@ describe('hooks', () => {
return <>{JSON.stringify(value)}>;
};
ReactDOM.render(
-
+
,
container
@@ -347,7 +362,14 @@ describe('hooks', () => {
expect(cnt).toBe(1);
act(() => {
- store.set({ foo: { bar: 'baz' } });
+ mutators.set({ foo: { bar: 'baz' } });
+ });
+
+ await new Promise(r => setTimeout(r, 1));
+ expect(cnt).toBe(1);
+
+ act(() => {
+ mutators.set({ foo: { bar: 'qux' } });
});
await new Promise(r => setTimeout(r, 1));
@@ -355,10 +377,15 @@ describe('hooks', () => {
});
test('can set custom comparator function to prevent re-renders on deep equality', async () => {
- const store = createStore({ foo: { bar: 'baz' } });
+ const { store, mutators } = create(
+ { foo: { bar: 'baz' } },
+ {
+ set: () => (newState: { foo: { bar: string } }) => newState,
+ }
+ );
const selector = (state: { foo: any }) => state.foo;
const comparator = (prev: any, curr: any) => JSON.stringify(prev) === JSON.stringify(curr);
- const { Provider, useSelector } = createContext(store);
+ const { Provider, useSelector } = createStateContainerReactHelpers();
let cnt = 0;
const Demo: React.FC<{}> = () => {
@@ -367,7 +394,7 @@ describe('hooks', () => {
return <>{JSON.stringify(value)}>;
};
ReactDOM.render(
-
+
,
container
@@ -377,7 +404,7 @@ describe('hooks', () => {
expect(cnt).toBe(1);
act(() => {
- store.set({ foo: { bar: 'baz' } });
+ mutators.set({ foo: { bar: 'baz' } });
});
await new Promise(r => setTimeout(r, 1));
diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.ts b/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.ts
new file mode 100644
index 0000000000000..e94165cc48376
--- /dev/null
+++ b/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.ts
@@ -0,0 +1,77 @@
+/*
+ * 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 React from 'react';
+import useObservable from 'react-use/lib/useObservable';
+import defaultComparator from 'fast-deep-equal';
+import { Comparator, Connect, StateContainer, UnboxState } from './types';
+
+const { useContext, useLayoutEffect, useRef, createElement: h } = React;
+
+export const createStateContainerReactHelpers = >() => {
+ const context = React.createContext(null as any);
+
+ const useContainer = (): Container => useContext(context);
+
+ const useState = (): UnboxState => {
+ const { state$, get } = useContainer();
+ const value = useObservable(state$, get());
+ return value;
+ };
+
+ const useTransitions = () => useContainer().transitions;
+
+ const useSelector = (
+ selector: (state: UnboxState) => Result,
+ comparator: Comparator = defaultComparator
+ ): Result => {
+ const { state$, get } = useContainer();
+ const lastValueRef = useRef(get());
+ const [value, setValue] = React.useState(() => {
+ const newValue = selector(get());
+ lastValueRef.current = newValue;
+ return newValue;
+ });
+ useLayoutEffect(() => {
+ const subscription = state$.subscribe((currentState: UnboxState) => {
+ const newValue = selector(currentState);
+ if (!comparator(lastValueRef.current, newValue)) {
+ lastValueRef.current = newValue;
+ setValue(newValue);
+ }
+ });
+ return () => subscription.unsubscribe();
+ }, [state$, comparator]);
+ return value;
+ };
+
+ const connect: Connect> = mapStateToProp => component => props =>
+ h(component, { ...useSelector(mapStateToProp), ...props } as any);
+
+ return {
+ Provider: context.Provider,
+ Consumer: context.Consumer,
+ context,
+ useContainer,
+ useState,
+ useTransitions,
+ useSelector,
+ connect,
+ };
+};
diff --git a/src/plugins/kibana_utils/public/state_containers/index.ts b/src/plugins/kibana_utils/public/state_containers/index.ts
new file mode 100644
index 0000000000000..43e204ecb79f7
--- /dev/null
+++ b/src/plugins/kibana_utils/public/state_containers/index.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 * from './types';
+export * from './create_state_container';
+export * from './create_state_container_react_helpers';
diff --git a/src/plugins/kibana_utils/public/state_containers/types.ts b/src/plugins/kibana_utils/public/state_containers/types.ts
new file mode 100644
index 0000000000000..e0a1a18972635
--- /dev/null
+++ b/src/plugins/kibana_utils/public/state_containers/types.ts
@@ -0,0 +1,99 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Observable } from 'rxjs';
+import { Ensure, RecursiveReadonly } from '@kbn/utility-types';
+
+export interface TransitionDescription {
+ type: Type;
+ args: Args;
+}
+export type Transition = (...args: Args) => State;
+export type PureTransition = (
+ state: RecursiveReadonly
+) => Transition;
+export type EnsurePureTransition = Ensure>;
+export type PureTransitionToTransition> = ReturnType;
+export type PureTransitionsToTransitions = {
+ [K in keyof T]: PureTransitionToTransition>;
+};
+
+export interface BaseStateContainer {
+ get: () => RecursiveReadonly;
+ set: (state: State) => void;
+ state$: Observable>;
+}
+
+export interface StateContainer<
+ State,
+ PureTransitions extends object,
+ PureSelectors extends object = {}
+> extends BaseStateContainer {
+ transitions: Readonly>;
+ selectors: Readonly>;
+}
+
+export interface ReduxLikeStateContainer<
+ State,
+ PureTransitions extends object,
+ PureSelectors extends object = {}
+> extends StateContainer {
+ getState: () => RecursiveReadonly;
+ reducer: Reducer>;
+ replaceReducer: (nextReducer: Reducer>) => void;
+ dispatch: (action: TransitionDescription) => void;
+ addMiddleware: (middleware: Middleware>) => void;
+ subscribe: (listener: (state: RecursiveReadonly) => void) => () => void;
+}
+
+export type Dispatch = (action: T) => void;
+
+export type Middleware = (
+ store: Pick, 'getState' | 'dispatch'>
+) => (
+ next: (action: TransitionDescription) => TransitionDescription | any
+) => Dispatch;
+
+export type Reducer = (state: State, action: TransitionDescription) => State;
+
+export type UnboxState<
+ Container extends StateContainer
+> = Container extends StateContainer ? T : never;
+export type UnboxTransitions<
+ Container extends StateContainer
+> = Container extends StateContainer ? T : never;
+
+export type Selector = (...args: Args) => Result;
+export type PureSelector = (
+ state: State
+) => Selector;
+export type EnsurePureSelector = Ensure>;
+export type PureSelectorToSelector> = ReturnType<
+ EnsurePureSelector
+>;
+export type PureSelectorsToSelectors = {
+ [K in keyof T]: PureSelectorToSelector>;
+};
+
+export type Comparator = (previous: Result, current: Result) => boolean;
+
+export type MapStateToProps = (state: State) => StateProps;
+export type Connect = (
+ mapStateToProp: MapStateToProps>
+) => (component: React.ComponentType) => React.FC>;
diff --git a/src/legacy/core_plugins/console/np_ready/public/application/models/index.ts b/src/plugins/kibana_utils/public/state_management/state_hash/index.ts
similarity index 96%
rename from src/legacy/core_plugins/console/np_ready/public/application/models/index.ts
rename to src/plugins/kibana_utils/public/state_management/state_hash/index.ts
index c4ac6f1454b7f..0e52c4c55872d 100644
--- a/src/legacy/core_plugins/console/np_ready/public/application/models/index.ts
+++ b/src/plugins/kibana_utils/public/state_management/state_hash/index.ts
@@ -17,4 +17,4 @@
* under the License.
*/
-export * from './legacy_editor';
+export * from './state_hash';
diff --git a/src/legacy/ui/public/state_management/state_hashing/state_hash.test.ts b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.test.ts
similarity index 91%
rename from src/legacy/ui/public/state_management/state_hashing/state_hash.test.ts
rename to src/plugins/kibana_utils/public/state_management/state_hash/state_hash.test.ts
index 83a94e37785c4..cccb74acaf1e5 100644
--- a/src/legacy/ui/public/state_management/state_hashing/state_hash.test.ts
+++ b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.test.ts
@@ -18,9 +18,8 @@
*/
import { encode as encodeRison } from 'rison-node';
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { mockStorage } from '../../../../../plugins/kibana_utils/public/storage/hashed_item_store/mock';
-import { createStateHash, isStateHash } from '../state_hashing';
+import { mockStorage } from '../../storage/hashed_item_store/mock';
+import { createStateHash, isStateHash } from './state_hash';
describe('stateHash', () => {
beforeEach(() => {
diff --git a/src/legacy/ui/public/state_management/state_hashing/state_hash.ts b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.ts
similarity index 96%
rename from src/legacy/ui/public/state_management/state_hashing/state_hash.ts
rename to src/plugins/kibana_utils/public/state_management/state_hash/state_hash.ts
index b3574876bafae..a3eb5272b112d 100644
--- a/src/legacy/ui/public/state_management/state_hashing/state_hash.ts
+++ b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.ts
@@ -18,7 +18,7 @@
*/
import { Sha256 } from '../../../../../core/public/utils';
-import { hashedItemStore } from '../../../../../plugins/kibana_utils/public';
+import { hashedItemStore } from '../../storage/hashed_item_store';
// This prefix is used to identify hash strings that have been encoded in the URL.
const HASH_PREFIX = 'h@';
diff --git a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.test.ts b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.test.ts
similarity index 97%
rename from src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.test.ts
rename to src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.test.ts
index afbe86a4b4d12..a85158acddefd 100644
--- a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.test.ts
+++ b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.test.ts
@@ -17,9 +17,8 @@
* under the License.
*/
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { mockStorage } from '../../../../../plugins/kibana_utils/public/storage/hashed_item_store/mock';
-import { HashedItemStore } from '../../../../../plugins/kibana_utils/public';
+import { mockStorage } from '../../storage/hashed_item_store/mock';
+import { HashedItemStore } from '../../storage/hashed_item_store';
import { hashUrl, unhashUrl } from './hash_unhash_url';
describe('hash unhash url', () => {
diff --git a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.ts b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.ts
similarity index 94%
rename from src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.ts
rename to src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.ts
index 7142683c25115..872e7953f938b 100644
--- a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.ts
+++ b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.ts
@@ -22,8 +22,8 @@ import rison, { RisonObject } from 'rison-node';
import { stringify as stringifyQueryString } from 'querystring';
import encodeUriQuery from 'encode-uri-query';
import { format as formatUrl, parse as parseUrl } from 'url';
-import { hashedItemStore } from '../../../../../plugins/kibana_utils/public';
-import { createStateHash, isStateHash } from './state_hash';
+import { hashedItemStore } from '../../storage/hashed_item_store';
+import { createStateHash, isStateHash } from '../state_hash';
export type IParsedUrlQuery = Record;
@@ -98,7 +98,7 @@ export function retrieveState(stateHash: string): RisonObject {
const json = hashedItemStore.getItem(stateHash);
const throwUnableToRestoreUrlError = () => {
throw new Error(
- i18n.translate('common.ui.stateManagement.unableToRestoreUrlErrorMessage', {
+ i18n.translate('kibana_utils.stateManagement.url.unableToRestoreUrlErrorMessage', {
defaultMessage:
'Unable to completely restore the URL, be sure to use the share functionality.',
})
@@ -125,7 +125,7 @@ export function persistState(state: RisonObject): string {
if (isItemSet) return hash;
// If we ran out of space trying to persist the state, notify the user.
const message = i18n.translate(
- 'common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage',
+ 'kibana_utils.stateManagement.url.unableToStoreHistoryInSessionErrorMessage',
{
defaultMessage:
'Kibana is unable to store history items in your session ' +
diff --git a/src/plugins/kibana_utils/public/store/index.ts b/src/plugins/kibana_utils/public/state_management/url/index.ts
similarity index 93%
rename from src/plugins/kibana_utils/public/store/index.ts
rename to src/plugins/kibana_utils/public/state_management/url/index.ts
index 468e8ab8c5ade..30c5696233db7 100644
--- a/src/plugins/kibana_utils/public/store/index.ts
+++ b/src/plugins/kibana_utils/public/state_management/url/index.ts
@@ -17,5 +17,4 @@
* under the License.
*/
-export * from './create_store';
-export * from './react';
+export * from './hash_unhash_url';
diff --git a/src/plugins/kibana_utils/public/store/create_store.test.ts b/src/plugins/kibana_utils/public/store/create_store.test.ts
deleted file mode 100644
index cfdeb76254003..0000000000000
--- a/src/plugins/kibana_utils/public/store/create_store.test.ts
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { createStore } from './create_store';
-
-test('can create store', () => {
- const store = createStore({});
- expect(store).toMatchObject({
- get: expect.any(Function),
- set: expect.any(Function),
- state$: expect.any(Object),
- createMutators: expect.any(Function),
- mutators: expect.any(Object),
- redux: {
- getState: expect.any(Function),
- dispatch: expect.any(Function),
- subscribe: expect.any(Function),
- },
- });
-});
-
-test('can set default state', () => {
- const defaultState = {
- foo: 'bar',
- };
- const store = createStore(defaultState);
- expect(store.get()).toEqual(defaultState);
- expect(store.redux.getState()).toEqual(defaultState);
-});
-
-test('can set state', () => {
- const defaultState = {
- foo: 'bar',
- };
- const newState = {
- foo: 'baz',
- };
- const store = createStore(defaultState);
-
- store.set(newState);
-
- expect(store.get()).toEqual(newState);
- expect(store.redux.getState()).toEqual(newState);
-});
-
-test('does not shallow merge states', () => {
- const defaultState = {
- foo: 'bar',
- };
- const newState = {
- foo2: 'baz',
- };
- const store = createStore(defaultState);
-
- store.set(newState);
-
- expect(store.get()).toEqual(newState);
- expect(store.redux.getState()).toEqual(newState);
-});
-
-test('can subscribe and unsubscribe to state changes', () => {
- const store = createStore({});
- const spy = jest.fn();
- const subscription = store.state$.subscribe(spy);
- store.set({ a: 1 });
- store.set({ a: 2 });
- subscription.unsubscribe();
- store.set({ a: 3 });
-
- expect(spy).toHaveBeenCalledTimes(2);
- expect(spy.mock.calls[0][0]).toEqual({ a: 1 });
- expect(spy.mock.calls[1][0]).toEqual({ a: 2 });
-});
-
-test('multiple subscribers can subscribe', () => {
- const store = createStore({});
- const spy1 = jest.fn();
- const spy2 = jest.fn();
- const subscription1 = store.state$.subscribe(spy1);
- const subscription2 = store.state$.subscribe(spy2);
- store.set({ a: 1 });
- subscription1.unsubscribe();
- store.set({ a: 2 });
- subscription2.unsubscribe();
- store.set({ a: 3 });
-
- expect(spy1).toHaveBeenCalledTimes(1);
- expect(spy2).toHaveBeenCalledTimes(2);
- expect(spy1.mock.calls[0][0]).toEqual({ a: 1 });
- expect(spy2.mock.calls[0][0]).toEqual({ a: 1 });
- expect(spy2.mock.calls[1][0]).toEqual({ a: 2 });
-});
-
-test('creates impure mutators from pure mutators', () => {
- const store = createStore({});
- const mutators = store.createMutators({
- setFoo: _ => bar => ({ foo: bar }),
- });
-
- expect(typeof mutators.setFoo).toBe('function');
-});
-
-test('mutators can update state', () => {
- const store = createStore({
- value: 0,
- foo: 'bar',
- });
- const mutators = store.createMutators({
- add: state => increment => ({ ...state, value: state.value + increment }),
- setFoo: state => bar => ({ ...state, foo: bar }),
- });
-
- expect(store.get()).toEqual({
- value: 0,
- foo: 'bar',
- });
-
- mutators.add(11);
- mutators.setFoo('baz');
-
- expect(store.get()).toEqual({
- value: 11,
- foo: 'baz',
- });
-
- mutators.add(-20);
- mutators.setFoo('bazooka');
-
- expect(store.get()).toEqual({
- value: -9,
- foo: 'bazooka',
- });
-});
-
-test('mutators methods are not bound', () => {
- const store = createStore({ value: -3 });
- const { add } = store.createMutators({
- add: state => increment => ({ ...state, value: state.value + increment }),
- });
-
- expect(store.get()).toEqual({ value: -3 });
- add(4);
- expect(store.get()).toEqual({ value: 1 });
-});
-
-test('created mutators are saved in store object', () => {
- const store = createStore<
- any,
- {
- add: (increment: number) => void;
- }
- >({ value: -3 });
-
- store.createMutators({
- add: state => increment => ({ ...state, value: state.value + increment }),
- });
-
- expect(typeof store.mutators.add).toBe('function');
- store.mutators.add(5);
- expect(store.get()).toEqual({ value: 2 });
-});
diff --git a/src/plugins/kibana_utils/public/store/create_store.ts b/src/plugins/kibana_utils/public/store/create_store.ts
deleted file mode 100644
index 315523360f92d..0000000000000
--- a/src/plugins/kibana_utils/public/store/create_store.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { createStore as createReduxStore, Reducer } from 'redux';
-import { Subject, Observable } from 'rxjs';
-import { AppStore, Mutators, PureMutators } from './types';
-
-const SET = '__SET__';
-
-export const createStore = <
- State extends {},
- StateMutators extends Mutators> = {}
->(
- defaultState: State
-): AppStore => {
- const pureMutators: PureMutators = {};
- const mutators: StateMutators = {} as StateMutators;
- const reducer: Reducer = (state, action) => {
- const pureMutator = pureMutators[action.type];
- if (pureMutator) {
- return pureMutator(state)(...action.args);
- }
-
- switch (action.type) {
- case SET:
- return action.state;
- default:
- return state;
- }
- };
- const redux = createReduxStore(reducer, defaultState as any);
-
- const get = redux.getState;
-
- const set = (state: State) =>
- redux.dispatch({
- type: SET,
- state,
- });
-
- const state$ = new Subject();
- redux.subscribe(() => {
- state$.next(get());
- });
-
- const createMutators: AppStore['createMutators'] = newPureMutators => {
- const result: Mutators = {};
- for (const type of Object.keys(newPureMutators)) {
- result[type] = (...args) => {
- redux.dispatch({
- type,
- args,
- });
- };
- }
- Object.assign(pureMutators, newPureMutators);
- Object.assign(mutators, result);
- return result;
- };
-
- return {
- get,
- set,
- redux,
- state$: (state$ as unknown) as Observable,
- createMutators,
- mutators,
- };
-};
diff --git a/src/plugins/kibana_utils/public/store/observable_selector.ts b/src/plugins/kibana_utils/public/store/observable_selector.ts
deleted file mode 100644
index 6ba6f42296a6c..0000000000000
--- a/src/plugins/kibana_utils/public/store/observable_selector.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { Observable, BehaviorSubject } from 'rxjs';
-
-export type Selector = (state: State) => Result;
-export type Comparator = (previous: Result, current: Result) => boolean;
-export type Unsubscribe = () => void;
-
-const defaultComparator: Comparator = (previous, current) => previous === current;
-
-export const observableSelector = (
- state: State,
- state$: Observable,
- selector: Selector,
- comparator: Comparator = defaultComparator
-): [Observable, Unsubscribe] => {
- let previousResult: Result = selector(state);
- const result$ = new BehaviorSubject