diff --git a/.eslintrc.js b/.eslintrc.js index 8d5b4525d51ba5..32f59c4d6b3db5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -888,7 +888,7 @@ module.exports = { { // typescript only for front and back end files: [ - 'x-pack/{,legacy/}plugins/{alerting,alerting_builtins,actions,task_manager,event_log}/**/*.{ts,tsx}', + 'x-pack/{,legacy/}plugins/{alerts,alerting_builtins,actions,task_manager,event_log}/**/*.{ts,tsx}', ], rules: { '@typescript-eslint/no-explicit-any': 'error', @@ -1039,5 +1039,22 @@ module.exports = { ...require('eslint-config-prettier/@typescript-eslint').rules, }, }, + + { + files: [ + // platform-team owned code + 'src/core/**', + 'x-pack/plugins/features/**', + 'x-pack/plugins/licensing/**', + 'x-pack/plugins/global_search/**', + 'x-pack/plugins/cloud/**', + 'packages/kbn-config-schema', + 'src/plugins/status_page/**', + 'src/plugins/saved_objects_management/**', + ], + rules: { + '@typescript-eslint/prefer-ts-expect-error': 'error', + }, + }, ], }; diff --git a/docs/apm/apm-alerts.asciidoc b/docs/apm/apm-alerts.asciidoc index 75ce5f56c96c65..bc5e1ccc1dd55e 100644 --- a/docs/apm/apm-alerts.asciidoc +++ b/docs/apm/apm-alerts.asciidoc @@ -15,15 +15,20 @@ and enables central management of all alerts from <>. + +The APM app supports two different types of threshold alerts: transaction duration, and error rate. Below, we'll create one of each. [float] [[apm-create-transaction-alert]] === Create a transaction duration alert -This guide creates an alert for the `opbeans-java` service based on the following criteria: +Transaction duration alerts trigger when the duration of a specific transaction type in a service exceeds a defined threshold. +This guide will create an alert for the `opbeans-java` service based on the following criteria: +* Environment: Production * Transaction type: `transaction.type:request` * Average request is above `1500ms` for the last 5 minutes * Check every 10 minutes, and repeat the alert every 30 minutes @@ -52,14 +57,22 @@ Enter a name for the connector, and paste the webhook URL. See Slack's webhook documentation if you need to create one. +Add a message body in markdown format. +You can use the https://mustache.github.io/[Mustache] template syntax, i.e., `{{variable}}` +to pass alert values at the time a condition is detected to an action. +A list of available variables can be accessed by selecting the +**add variable** button image:apm/images/add-variable.png[add variable button]. + Select **Save**. The alert has been created and is now active! [float] [[apm-create-error-alert]] === Create an error rate alert +Error rate alerts trigger when the number of errors in a service exceeds a defined threshold. This guide creates an alert for the `opbeans-python` service based on the following criteria: +* Environment: Production * Error rate is above 25 for the last minute * Check every 1 minute, and repeat the alert every 10 minutes * Send the alert via email to the `opbeans-python` team @@ -81,6 +94,12 @@ Based on the alert criteria, define the following alert details: Select the **Email** action type and click **Create a connector**. Fill out the required details: sender, host, port, etc., and click **save**. +Add a message body in markdown format. +You can use the https://mustache.github.io/[Mustache] template syntax, i.e., `{{variable}}` +to pass alert values at the time a condition is detected to an action. +A list of available variables can be accessed by selecting the +**add variable** button image:apm/images/add-variable.png[add variable button]. + Select **Save**. The alert has been created and is now active! [float] diff --git a/docs/apm/images/add-variable.png b/docs/apm/images/add-variable.png new file mode 100644 index 00000000000000..860ab66f22f4e2 Binary files /dev/null and b/docs/apm/images/add-variable.png differ diff --git a/docs/apm/troubleshooting.asciidoc b/docs/apm/troubleshooting.asciidoc index eb4fb790afd7fd..65f7a378ec2443 100644 --- a/docs/apm/troubleshooting.asciidoc +++ b/docs/apm/troubleshooting.asciidoc @@ -10,6 +10,11 @@ your proposed changes at https://github.com/elastic/kibana. Also, check out the https://discuss.elastic.co/c/apm[APM discussion forum]. +* <> +* <> +* <> +* <> + [float] [[no-apm-data-found]] === No APM data found @@ -58,6 +63,66 @@ Navigate to *APM* > *Settings* > *Indices*, and change all `apm_oss.*Pattern` va include the new index pattern. For example: `customIndexName-*`. [float] +[[troubleshooting-too-many-transactions]] +=== Too many unique transaction names + +Transaction names are defined in each APM Agent; when an Agent supports a framework, +it includes logic for naming the transactions that the framework creates. +In some cases though, like when using an Agent's API to create custom transactions, +it is up to the user to define a pattern for transaction naming. +When transactions are named incorrectly, each unique URL can be associated with a unique transaction group—causing +an explosion in the number of transaction groups per service, and leading to inaccuracies in the APM app. + +To fix a large number of unique transaction names, +you need to change how you are using the Agent API to name your transactions. +To do this, ensure you are **not** naming based on parameters that can change. +For example, user ids, product ids, order numbers, query parameters, etc., +should be stripped away, and commonality should be found between your unique URLs. + +Let's look at an example from the RUM Agent documentation. Here are a few URLs you might find on Elastic.co: + +[source,yml] +---- +// Blog Posts +https://www.elastic.co/blog/reflections-on-three-years-in-the-elastic-public-sector +https://www.elastic.co/blog/say-heya-to-the-elastic-search-awards +https://www.elastic.co/blog/and-the-winner-of-the-elasticon-2018-training-subscription-drawing-is + +// Documentation +https://www.elastic.co/guide/en/elastic-stack/current/index.html +https://www.elastic.co/guide/en/apm/get-started/current/index.html +https://www.elastic.co/guide/en/infrastructure/guide/current/index.html +---- + +These URLs, like most, include unique names. +If we named transactions based on each unique URL, we'd end up with the problem described above—a +very large number of different transaction names. +Instead, we should strip away the unique information and group our transactions based on common information. +In this case, that means naming all blog transactions, `/blog`, and all documentation transactions, `/guide`. + +If you feel like you'd be losing valuable information by following this naming convention, don't fret! +You can always add additional metadata to your transactions using {apm-overview-ref-v}/metadata.html#labels-fields[labels] (indexed) or +{apm-overview-ref-v}/metadata.html#custom-fields[custom context] (non-indexed). + +After ensuring you've correctly named your transactions, +you might still see an error in the APM app related to too many transaction names. +If this is the case, you can increase the default number of transaction groups displayed in the APM app by configuring +<>. + +**More information** + +While this can happen with any APM Agent, it typically occurs with the RUM Agent. +For more information on how to correctly set `transaction.name` in the RUM Agent, +see {apm-rum-ref}/custom-transaction-name.html[custom initial page load transaction names]. + +The RUM Agent can also set the `transaction.name` when observing for transaction events. +See {apm-rum-ref}/agent-api.html#observe[`apm.observe()`] for more information. + +If your problem is occurring in a different Agent, the tips above still apply. +See the relevant {apm-agents-ref}[Agent API documentation] to adjust how you're naming your transactions. + +[float] +[[troubleshooting-unknown-route]] === Unknown route The {apm-app-ref}/transactions.html[transaction overview] will only display helpful information @@ -78,6 +143,7 @@ Specifically, view the Agent's supported technologies page. You can also use the Agent's public API to manually set a name for the transaction. [float] +[[troubleshooting-fields-unsearchable]] === Fields are not searchable In Elasticsearch, index templates are used to define settings and mappings that determine how fields should be analyzed. diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index b0612ff4d5b65f..8f2bde3856019a 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -172,7 +172,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [PublicAppInfo](./kibana-plugin-core-public.publicappinfo.md) | Public information about a registered [application](./kibana-plugin-core-public.app.md) | | [PublicLegacyAppInfo](./kibana-plugin-core-public.publiclegacyappinfo.md) | Information about a registered [legacy application](./kibana-plugin-core-public.legacyapp.md) | | [PublicUiSettingsParams](./kibana-plugin-core-public.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) exposed to the client-side. | -| [RecursiveReadonly](./kibana-plugin-core-public.recursivereadonly.md) | | | [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | Type definition for a Saved Object attribute value | | [SavedObjectAttributeSingle](./kibana-plugin-core-public.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | | [SavedObjectsClientContract](./kibana-plugin-core-public.savedobjectsclientcontract.md) | SavedObjectsClientContract as implemented by the [SavedObjectsClient](./kibana-plugin-core-public.savedobjectsclient.md) | diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md index c70f3a97a8882f..4b3b103c92731d 100644 --- a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md +++ b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md @@ -11,5 +11,8 @@ Public information about a registered [application](./kibana-plugin-core-public. ```typescript export declare type PublicAppInfo = Omit & { legacy: false; + status: AppStatus; + navLinkStatus: AppNavLinkStatus; + appRoute: string; }; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publiclegacyappinfo.md b/docs/development/core/public/kibana-plugin-core-public.publiclegacyappinfo.md index cc3e9de3193cb8..051638daabd12f 100644 --- a/docs/development/core/public/kibana-plugin-core-public.publiclegacyappinfo.md +++ b/docs/development/core/public/kibana-plugin-core-public.publiclegacyappinfo.md @@ -11,5 +11,7 @@ Information about a registered [legacy application](./kibana-plugin-core-public. ```typescript export declare type PublicLegacyAppInfo = Omit & { legacy: true; + status: AppStatus; + navLinkStatus: AppNavLinkStatus; }; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.recursivereadonly.md b/docs/development/core/public/kibana-plugin-core-public.recursivereadonly.md deleted file mode 100644 index 2f47ef1086d717..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.recursivereadonly.md +++ /dev/null @@ -1,14 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [RecursiveReadonly](./kibana-plugin-core-public.recursivereadonly.md) - -## RecursiveReadonly type - - -Signature: - -```typescript -export declare 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/docs/development/core/server/kibana-plugin-core-server.callapioptions.md b/docs/development/core/server/kibana-plugin-core-server.callapioptions.md deleted file mode 100644 index 03f74424acf99b..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.callapioptions.md +++ /dev/null @@ -1,21 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CallAPIOptions](./kibana-plugin-core-server.callapioptions.md) - -## CallAPIOptions interface - -The set of options that defines how API call should be made and result be processed. - -Signature: - -```typescript -export interface CallAPIOptions -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [signal](./kibana-plugin-core-server.callapioptions.signal.md) | AbortSignal | A signal object that allows you to abort the request via an AbortController object. | -| [wrap401Errors](./kibana-plugin-core-server.callapioptions.wrap401errors.md) | boolean | Indicates whether 401 Unauthorized errors returned from the Elasticsearch API should be wrapped into Boom error instances with properly set WWW-Authenticate header that could have been returned by the API itself. If API didn't specify that then Basic realm="Authorization Required" is used as WWW-Authenticate. | - diff --git a/docs/development/core/server/kibana-plugin-core-server.clusterclient._constructor_.md b/docs/development/core/server/kibana-plugin-core-server.clusterclient._constructor_.md deleted file mode 100644 index d4b2f80443acb6..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.clusterclient._constructor_.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ClusterClient](./kibana-plugin-core-server.clusterclient.md) > [(constructor)](./kibana-plugin-core-server.clusterclient._constructor_.md) - -## ClusterClient.(constructor) - -Constructs a new instance of the `ClusterClient` class - -Signature: - -```typescript -constructor(config: ElasticsearchClientConfig, log: Logger, getAuthHeaders?: GetAuthHeaders); -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| config | ElasticsearchClientConfig | | -| log | Logger | | -| getAuthHeaders | GetAuthHeaders | | - diff --git a/docs/development/core/server/kibana-plugin-core-server.clusterclient.asscoped.md b/docs/development/core/server/kibana-plugin-core-server.clusterclient.asscoped.md deleted file mode 100644 index dd1dcffc5a969f..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.clusterclient.asscoped.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ClusterClient](./kibana-plugin-core-server.clusterclient.md) > [asScoped](./kibana-plugin-core-server.clusterclient.asscoped.md) - -## ClusterClient.asScoped() method - -Creates an instance of [IScopedClusterClient](./kibana-plugin-core-server.iscopedclusterclient.md) based on the configuration the current cluster client that exposes additional `callAsCurrentUser` method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. - -Signature: - -```typescript -asScoped(request?: ScopeableRequest): IScopedClusterClient; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| request | ScopeableRequest | Request the IScopedClusterClient instance will be scoped to. Supports request optionality, Legacy.Request & FakeRequest for BWC with LegacyPlatform | - -Returns: - -`IScopedClusterClient` - diff --git a/docs/development/core/server/kibana-plugin-core-server.clusterclient.callasinternaluser.md b/docs/development/core/server/kibana-plugin-core-server.clusterclient.callasinternaluser.md deleted file mode 100644 index ae9a9b46b52b6b..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.clusterclient.callasinternaluser.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ClusterClient](./kibana-plugin-core-server.clusterclient.md) > [callAsInternalUser](./kibana-plugin-core-server.clusterclient.callasinternaluser.md) - -## ClusterClient.callAsInternalUser property - -Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-core-server.apicaller.md). - -Signature: - -```typescript -callAsInternalUser: APICaller; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.clusterclient.md b/docs/development/core/server/kibana-plugin-core-server.clusterclient.md deleted file mode 100644 index 0f6b2512a6d94c..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.clusterclient.md +++ /dev/null @@ -1,35 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ClusterClient](./kibana-plugin-core-server.clusterclient.md) - -## ClusterClient class - -Represents an Elasticsearch cluster API client created by the platform. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via `asScoped(...)`). - -See [ClusterClient](./kibana-plugin-core-server.clusterclient.md). - -Signature: - -```typescript -export declare class ClusterClient implements IClusterClient -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(config, log, getAuthHeaders)](./kibana-plugin-core-server.clusterclient._constructor_.md) | | Constructs a new instance of the ClusterClient class | - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [callAsInternalUser](./kibana-plugin-core-server.clusterclient.callasinternaluser.md) | | APICaller | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-core-server.apicaller.md). | - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [asScoped(request)](./kibana-plugin-core-server.clusterclient.asscoped.md) | | Creates an instance of [IScopedClusterClient](./kibana-plugin-core-server.iscopedclusterclient.md) based on the configuration the current cluster client that exposes additional callAsCurrentUser method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. | -| [close()](./kibana-plugin-core-server.clusterclient.close.md) | | Closes the cluster client. After that client cannot be used and one should create a new client instance to be able to interact with Elasticsearch API. | - diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherror._code_.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherror._code_.md deleted file mode 100644 index d2b07e8d116bab..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherror._code_.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchError](./kibana-plugin-core-server.elasticsearcherror.md) > [\[code\]](./kibana-plugin-core-server.elasticsearcherror._code_.md) - -## ElasticsearchError.\[code\] property - -Signature: - -```typescript -[code]?: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherror.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherror.md deleted file mode 100644 index 42079c02689c53..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherror.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchError](./kibana-plugin-core-server.elasticsearcherror.md) - -## ElasticsearchError interface - - -Signature: - -```typescript -export interface ElasticsearchError extends Boom -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [\[code\]](./kibana-plugin-core-server.elasticsearcherror._code_.md) | string | | - diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.isnotauthorizederror.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.isnotauthorizederror.md deleted file mode 100644 index d85ae4f9ab5303..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.isnotauthorizederror.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorHelpers](./kibana-plugin-core-server.elasticsearcherrorhelpers.md) > [isNotAuthorizedError](./kibana-plugin-core-server.elasticsearcherrorhelpers.isnotauthorizederror.md) - -## ElasticsearchErrorHelpers.isNotAuthorizedError() method - -Signature: - -```typescript -static isNotAuthorizedError(error: any): error is ElasticsearchError; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| error | any | | - -Returns: - -`error is ElasticsearchError` - diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md index e8c4c63dc6a964..c683f0ba33189f 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md @@ -13,7 +13,7 @@ ```typescript legacy: { - readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; - readonly client: IClusterClient; + readonly createClient: (type: string, clientConfig?: Partial) => ILegacyCustomClusterClient; + readonly client: ILegacyClusterClient; }; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md index c1e23527e95163..0dd41a6154a1e8 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md @@ -15,5 +15,5 @@ export interface ElasticsearchServiceSetup | Property | Type | Description | | --- | --- | --- | -| [legacy](./kibana-plugin-core-server.elasticsearchservicesetup.legacy.md) | {
readonly createClient: (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => ICustomClusterClient;
readonly client: IClusterClient;
} | | +| [legacy](./kibana-plugin-core-server.elasticsearchservicesetup.legacy.md) | {
readonly createClient: (type: string, clientConfig?: Partial<LegacyElasticsearchClientConfig>) => ILegacyCustomClusterClient;
readonly client: ILegacyClusterClient;
} | | diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md index 667a36091f2326..5f346d7887c2af 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md @@ -13,7 +13,7 @@ ```typescript legacy: { - readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; - readonly client: IClusterClient; + readonly createClient: (type: string, clientConfig?: Partial) => ILegacyCustomClusterClient; + readonly client: ILegacyClusterClient; }; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md index 39c794af2c881f..e059acdbd52fa2 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md @@ -15,5 +15,5 @@ export interface ElasticsearchServiceStart | Property | Type | Description | | --- | --- | --- | -| [legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) | {
readonly createClient: (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => ICustomClusterClient;
readonly client: IClusterClient;
} | | +| [legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) | {
readonly createClient: (type: string, clientConfig?: Partial<LegacyElasticsearchClientConfig>) => ILegacyCustomClusterClient;
readonly client: ILegacyClusterClient;
} | | diff --git a/docs/development/core/server/kibana-plugin-core-server.iclusterclient.md b/docs/development/core/server/kibana-plugin-core-server.ilegacyclusterclient.md similarity index 56% rename from docs/development/core/server/kibana-plugin-core-server.iclusterclient.md rename to docs/development/core/server/kibana-plugin-core-server.ilegacyclusterclient.md index 28fbdf17cf31c9..c70a5ac07c6ad8 100644 --- a/docs/development/core/server/kibana-plugin-core-server.iclusterclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.ilegacyclusterclient.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IClusterClient](./kibana-plugin-core-server.iclusterclient.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ILegacyClusterClient](./kibana-plugin-core-server.ilegacyclusterclient.md) -## IClusterClient type +## ILegacyClusterClient type Represents an Elasticsearch cluster API client created by the platform. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via `asScoped(...)`). -See [ClusterClient](./kibana-plugin-core-server.clusterclient.md). +See [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md). Signature: ```typescript -export declare type IClusterClient = Pick; +export declare type ILegacyClusterClient = Pick; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.icustomclusterclient.md b/docs/development/core/server/kibana-plugin-core-server.ilegacycustomclusterclient.md similarity index 53% rename from docs/development/core/server/kibana-plugin-core-server.icustomclusterclient.md rename to docs/development/core/server/kibana-plugin-core-server.ilegacycustomclusterclient.md index 3d379e1231cb15..a3cb8f13150212 100644 --- a/docs/development/core/server/kibana-plugin-core-server.icustomclusterclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.ilegacycustomclusterclient.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ICustomClusterClient](./kibana-plugin-core-server.icustomclusterclient.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ILegacyCustomClusterClient](./kibana-plugin-core-server.ilegacycustomclusterclient.md) -## ICustomClusterClient type +## ILegacyCustomClusterClient type Represents an Elasticsearch cluster API client created by a plugin. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via `asScoped(...)`). -See [ClusterClient](./kibana-plugin-core-server.clusterclient.md). +See [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md). Signature: ```typescript -export declare type ICustomClusterClient = Pick; +export declare type ILegacyCustomClusterClient = Pick; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.iscopedclusterclient.md b/docs/development/core/server/kibana-plugin-core-server.ilegacyscopedclusterclient.md similarity index 56% rename from docs/development/core/server/kibana-plugin-core-server.iscopedclusterclient.md rename to docs/development/core/server/kibana-plugin-core-server.ilegacyscopedclusterclient.md index 378836ee461f38..1263b85acb4983 100644 --- a/docs/development/core/server/kibana-plugin-core-server.iscopedclusterclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.ilegacyscopedclusterclient.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IScopedClusterClient](./kibana-plugin-core-server.iscopedclusterclient.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ILegacyScopedClusterClient](./kibana-plugin-core-server.ilegacyscopedclusterclient.md) -## IScopedClusterClient type +## ILegacyScopedClusterClient type Serves the same purpose as "normal" `ClusterClient` but exposes additional `callAsCurrentUser` method that doesn't use credentials of the Kibana internal user (as `callAsInternalUser` does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API. -See [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md). +See [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md). Signature: ```typescript -export declare type IScopedClusterClient = Pick; +export declare type ILegacyScopedClusterClient = Pick; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.apicaller.md b/docs/development/core/server/kibana-plugin-core-server.legacyapicaller.md similarity index 54% rename from docs/development/core/server/kibana-plugin-core-server.apicaller.md rename to docs/development/core/server/kibana-plugin-core-server.legacyapicaller.md index 4da23b3f821c5b..e6c2878d2b3556 100644 --- a/docs/development/core/server/kibana-plugin-core-server.apicaller.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyapicaller.md @@ -1,12 +1,12 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [APICaller](./kibana-plugin-core-server.apicaller.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md) -## APICaller interface +## LegacyAPICaller interface Signature: ```typescript -export interface APICaller +export interface LegacyAPICaller ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.md b/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.md new file mode 100644 index 00000000000000..9ebe2fc57a54bf --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyCallAPIOptions](./kibana-plugin-core-server.legacycallapioptions.md) + +## LegacyCallAPIOptions interface + +The set of options that defines how API call should be made and result be processed. + +Signature: + +```typescript +export interface LegacyCallAPIOptions +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [signal](./kibana-plugin-core-server.legacycallapioptions.signal.md) | AbortSignal | A signal object that allows you to abort the request via an AbortController object. | +| [wrap401Errors](./kibana-plugin-core-server.legacycallapioptions.wrap401errors.md) | boolean | Indicates whether 401 Unauthorized errors returned from the Elasticsearch API should be wrapped into Boom error instances with properly set WWW-Authenticate header that could have been returned by the API itself. If API didn't specify that then Basic realm="Authorization Required" is used as WWW-Authenticate. | + diff --git a/docs/development/core/server/kibana-plugin-core-server.callapioptions.signal.md b/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.signal.md similarity index 57% rename from docs/development/core/server/kibana-plugin-core-server.callapioptions.signal.md rename to docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.signal.md index 8b35924826f151..7d795a59e41a54 100644 --- a/docs/development/core/server/kibana-plugin-core-server.callapioptions.signal.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.signal.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CallAPIOptions](./kibana-plugin-core-server.callapioptions.md) > [signal](./kibana-plugin-core-server.callapioptions.signal.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyCallAPIOptions](./kibana-plugin-core-server.legacycallapioptions.md) > [signal](./kibana-plugin-core-server.legacycallapioptions.signal.md) -## CallAPIOptions.signal property +## LegacyCallAPIOptions.signal property A signal object that allows you to abort the request via an AbortController object. diff --git a/docs/development/core/server/kibana-plugin-core-server.callapioptions.wrap401errors.md b/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.wrap401errors.md similarity index 69% rename from docs/development/core/server/kibana-plugin-core-server.callapioptions.wrap401errors.md rename to docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.wrap401errors.md index 2a5b8054819a3a..38fac54db77a42 100644 --- a/docs/development/core/server/kibana-plugin-core-server.callapioptions.wrap401errors.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacycallapioptions.wrap401errors.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CallAPIOptions](./kibana-plugin-core-server.callapioptions.md) > [wrap401Errors](./kibana-plugin-core-server.callapioptions.wrap401errors.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyCallAPIOptions](./kibana-plugin-core-server.legacycallapioptions.md) > [wrap401Errors](./kibana-plugin-core-server.legacycallapioptions.wrap401errors.md) -## CallAPIOptions.wrap401Errors property +## LegacyCallAPIOptions.wrap401Errors property Indicates whether `401 Unauthorized` errors returned from the Elasticsearch API should be wrapped into `Boom` error instances with properly set `WWW-Authenticate` header that could have been returned by the API itself. If API didn't specify that then `Basic realm="Authorization Required"` is used as `WWW-Authenticate`. diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient._constructor_.md b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient._constructor_.md new file mode 100644 index 00000000000000..823f34bd7dd237 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient._constructor_.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md) > [(constructor)](./kibana-plugin-core-server.legacyclusterclient._constructor_.md) + +## LegacyClusterClient.(constructor) + +Constructs a new instance of the `LegacyClusterClient` class + +Signature: + +```typescript +constructor(config: LegacyElasticsearchClientConfig, log: Logger, getAuthHeaders?: GetAuthHeaders); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| config | LegacyElasticsearchClientConfig | | +| log | Logger | | +| getAuthHeaders | GetAuthHeaders | | + diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.asscoped.md b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.asscoped.md new file mode 100644 index 00000000000000..1c25fc1d072b61 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.asscoped.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md) > [asScoped](./kibana-plugin-core-server.legacyclusterclient.asscoped.md) + +## LegacyClusterClient.asScoped() method + +Creates an instance of [ILegacyScopedClusterClient](./kibana-plugin-core-server.ilegacyscopedclusterclient.md) based on the configuration the current cluster client that exposes additional `callAsCurrentUser` method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. + +Signature: + +```typescript +asScoped(request?: ScopeableRequest): ILegacyScopedClusterClient; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| request | ScopeableRequest | Request the IScopedClusterClient instance will be scoped to. Supports request optionality, Legacy.Request & FakeRequest for BWC with LegacyPlatform | + +Returns: + +`ILegacyScopedClusterClient` + diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.callasinternaluser.md b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.callasinternaluser.md new file mode 100644 index 00000000000000..2e235485711c6e --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.callasinternaluser.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md) > [callAsInternalUser](./kibana-plugin-core-server.legacyclusterclient.callasinternaluser.md) + +## LegacyClusterClient.callAsInternalUser property + +Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md). + +Signature: + +```typescript +callAsInternalUser: LegacyAPICaller; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.clusterclient.close.md b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.close.md similarity index 64% rename from docs/development/core/server/kibana-plugin-core-server.clusterclient.close.md rename to docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.close.md index 68a1bd4b9d7cf2..88a5ffce5bb17c 100644 --- a/docs/development/core/server/kibana-plugin-core-server.clusterclient.close.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.close.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ClusterClient](./kibana-plugin-core-server.clusterclient.md) > [close](./kibana-plugin-core-server.clusterclient.close.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md) > [close](./kibana-plugin-core-server.legacyclusterclient.close.md) -## ClusterClient.close() method +## LegacyClusterClient.close() method Closes the cluster client. After that client cannot be used and one should create a new client instance to be able to interact with Elasticsearch API. diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.md b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.md new file mode 100644 index 00000000000000..4f218ae552c99b --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyclusterclient.md @@ -0,0 +1,32 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md) + +## LegacyClusterClient class + + +Signature: + +```typescript +export declare class LegacyClusterClient implements ILegacyClusterClient +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(config, log, getAuthHeaders)](./kibana-plugin-core-server.legacyclusterclient._constructor_.md) | | Constructs a new instance of the LegacyClusterClient class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [callAsInternalUser](./kibana-plugin-core-server.legacyclusterclient.callasinternaluser.md) | | LegacyAPICaller | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md). | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [asScoped(request)](./kibana-plugin-core-server.legacyclusterclient.asscoped.md) | | Creates an instance of [ILegacyScopedClusterClient](./kibana-plugin-core-server.ilegacyscopedclusterclient.md) based on the configuration the current cluster client that exposes additional callAsCurrentUser method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. | +| [close()](./kibana-plugin-core-server.legacyclusterclient.close.md) | | Closes the cluster client. After that client cannot be used and one should create a new client instance to be able to interact with Elasticsearch API. | + diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearchclientconfig.md similarity index 52% rename from docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md rename to docs/development/core/server/kibana-plugin-core-server.legacyelasticsearchclientconfig.md index 703b07808aca3b..62b0f216c863c0 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearchclientconfig.md @@ -1,14 +1,14 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchClientConfig](./kibana-plugin-core-server.elasticsearchclientconfig.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyElasticsearchClientConfig](./kibana-plugin-core-server.legacyelasticsearchclientconfig.md) -## ElasticsearchClientConfig type +## LegacyElasticsearchClientConfig type Signature: ```typescript -export declare type ElasticsearchClientConfig = Pick & Pick & { +export declare type LegacyElasticsearchClientConfig = Pick & Pick & { pingTimeout?: ElasticsearchConfig['pingTimeout'] | ConfigOptions['pingTimeout']; requestTimeout?: ElasticsearchConfig['requestTimeout'] | ConfigOptions['requestTimeout']; sniffInterval?: ElasticsearchConfig['sniffInterval'] | ConfigOptions['sniffInterval']; diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror._code_.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror._code_.md new file mode 100644 index 00000000000000..05530ceb0d568b --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror._code_.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyElasticsearchError](./kibana-plugin-core-server.legacyelasticsearcherror.md) > [\[code\]](./kibana-plugin-core-server.legacyelasticsearcherror._code_.md) + +## LegacyElasticsearchError.\[code\] property + +Signature: + +```typescript +[code]?: string; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md new file mode 100644 index 00000000000000..f760780504e55f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyElasticsearchError](./kibana-plugin-core-server.legacyelasticsearcherror.md) + +## LegacyElasticsearchError interface + + +Signature: + +```typescript +export interface LegacyElasticsearchError extends Boom +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [\[code\]](./kibana-plugin-core-server.legacyelasticsearcherror._code_.md) | string | | + diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.decoratenotauthorizederror.md similarity index 52% rename from docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md rename to docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.decoratenotauthorizederror.md index 2b2eeceb4e3c9d..bd802a39e9339f 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.decoratenotauthorizederror.md @@ -1,13 +1,13 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorHelpers](./kibana-plugin-core-server.elasticsearcherrorhelpers.md) > [decorateNotAuthorizedError](./kibana-plugin-core-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyElasticsearchErrorHelpers](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md) > [decorateNotAuthorizedError](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.decoratenotauthorizederror.md) -## ElasticsearchErrorHelpers.decorateNotAuthorizedError() method +## LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError() method Signature: ```typescript -static decorateNotAuthorizedError(error: Error, reason?: string): ElasticsearchError; +static decorateNotAuthorizedError(error: Error, reason?: string): LegacyElasticsearchError; ``` ## Parameters @@ -19,5 +19,5 @@ static decorateNotAuthorizedError(error: Error, reason?: string): ElasticsearchE Returns: -`ElasticsearchError` +`LegacyElasticsearchError` diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.isnotauthorizederror.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.isnotauthorizederror.md new file mode 100644 index 00000000000000..f647916149458e --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.isnotauthorizederror.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyElasticsearchErrorHelpers](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md) > [isNotAuthorizedError](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.isnotauthorizederror.md) + +## LegacyElasticsearchErrorHelpers.isNotAuthorizedError() method + +Signature: + +```typescript +static isNotAuthorizedError(error: any): error is LegacyElasticsearchError; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| error | any | | + +Returns: + +`error is LegacyElasticsearchError` + diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md similarity index 65% rename from docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.md rename to docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md index e9c205e3dfa2c4..e20dcd4ed253eb 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrorhelpers.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorHelpers](./kibana-plugin-core-server.elasticsearcherrorhelpers.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyElasticsearchErrorHelpers](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md) -## ElasticsearchErrorHelpers class +## LegacyElasticsearchErrorHelpers class Helpers for working with errors returned from the Elasticsearch service.Since the internal data of errors are subject to change, consumers of the Elasticsearch service should always use these helpers to classify errors instead of checking error internals such as `body.error.header[WWW-Authenticate]` Signature: ```typescript -export declare class ElasticsearchErrorHelpers +export declare class LegacyElasticsearchErrorHelpers ``` ## Example @@ -30,6 +30,6 @@ try { | Method | Modifiers | Description | | --- | --- | --- | -| [decorateNotAuthorizedError(error, reason)](./kibana-plugin-core-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md) | static | | -| [isNotAuthorizedError(error)](./kibana-plugin-core-server.elasticsearcherrorhelpers.isnotauthorizederror.md) | static | | +| [decorateNotAuthorizedError(error, reason)](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.decoratenotauthorizederror.md) | static | | +| [isNotAuthorizedError(error)](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.isnotauthorizederror.md) | static | | diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient._constructor_.md b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient._constructor_.md new file mode 100644 index 00000000000000..bd1cd1e9f3d9b3 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient._constructor_.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md) > [(constructor)](./kibana-plugin-core-server.legacyscopedclusterclient._constructor_.md) + +## LegacyScopedClusterClient.(constructor) + +Constructs a new instance of the `LegacyScopedClusterClient` class + +Signature: + +```typescript +constructor(internalAPICaller: LegacyAPICaller, scopedAPICaller: LegacyAPICaller, headers?: Headers | undefined); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| internalAPICaller | LegacyAPICaller | | +| scopedAPICaller | LegacyAPICaller | | +| headers | Headers | undefined | | + diff --git a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.callascurrentuser.md b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.callascurrentuser.md similarity index 58% rename from docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.callascurrentuser.md rename to docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.callascurrentuser.md index 68c0f8e6be1be0..9130f9adde76e0 100644 --- a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.callascurrentuser.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.callascurrentuser.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md) > [callAsCurrentUser](./kibana-plugin-core-server.scopedclusterclient.callascurrentuser.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md) > [callAsCurrentUser](./kibana-plugin-core-server.legacyscopedclusterclient.callascurrentuser.md) -## ScopedClusterClient.callAsCurrentUser() method +## LegacyScopedClusterClient.callAsCurrentUser() method -Calls specified `endpoint` with provided `clientParams` on behalf of the user initiated request to the Kibana server (via HTTP request headers). See [APICaller](./kibana-plugin-core-server.apicaller.md). +Calls specified `endpoint` with provided `clientParams` on behalf of the user initiated request to the Kibana server (via HTTP request headers). See [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md). Signature: ```typescript -callAsCurrentUser(endpoint: string, clientParams?: Record, options?: CallAPIOptions): Promise; +callAsCurrentUser(endpoint: string, clientParams?: Record, options?: LegacyCallAPIOptions): Promise; ``` ## Parameters @@ -18,7 +18,7 @@ callAsCurrentUser(endpoint: string, clientParams?: Record, options? | --- | --- | --- | | endpoint | string | String descriptor of the endpoint e.g. cluster.getSettings or ping. | | clientParams | Record<string, any> | A dictionary of parameters that will be passed directly to the Elasticsearch JS client. | -| options | CallAPIOptions | Options that affect the way we call the API and process the result. | +| options | LegacyCallAPIOptions | Options that affect the way we call the API and process the result. | Returns: diff --git a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.callasinternaluser.md b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.callasinternaluser.md similarity index 55% rename from docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.callasinternaluser.md rename to docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.callasinternaluser.md index e769fd692a4d1d..bf95782299e720 100644 --- a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.callasinternaluser.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.callasinternaluser.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md) > [callAsInternalUser](./kibana-plugin-core-server.scopedclusterclient.callasinternaluser.md) +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md) > [callAsInternalUser](./kibana-plugin-core-server.legacyscopedclusterclient.callasinternaluser.md) -## ScopedClusterClient.callAsInternalUser() method +## LegacyScopedClusterClient.callAsInternalUser() method -Calls specified `endpoint` with provided `clientParams` on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-core-server.apicaller.md). +Calls specified `endpoint` with provided `clientParams` on behalf of the Kibana internal user. See [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md). Signature: ```typescript -callAsInternalUser(endpoint: string, clientParams?: Record, options?: CallAPIOptions): Promise; +callAsInternalUser(endpoint: string, clientParams?: Record, options?: LegacyCallAPIOptions): Promise; ``` ## Parameters @@ -18,7 +18,7 @@ callAsInternalUser(endpoint: string, clientParams?: Record, options | --- | --- | --- | | endpoint | string | String descriptor of the endpoint e.g. cluster.getSettings or ping. | | clientParams | Record<string, any> | A dictionary of parameters that will be passed directly to the Elasticsearch JS client. | -| options | CallAPIOptions | Options that affect the way we call the API and process the result. | +| options | LegacyCallAPIOptions | Options that affect the way we call the API and process the result. | Returns: diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.md b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.md new file mode 100644 index 00000000000000..f3d8a69b8ed053 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.legacyscopedclusterclient.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md) + +## LegacyScopedClusterClient class + + +Signature: + +```typescript +export declare class LegacyScopedClusterClient implements ILegacyScopedClusterClient +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(internalAPICaller, scopedAPICaller, headers)](./kibana-plugin-core-server.legacyscopedclusterclient._constructor_.md) | | Constructs a new instance of the LegacyScopedClusterClient class | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [callAsCurrentUser(endpoint, clientParams, options)](./kibana-plugin-core-server.legacyscopedclusterclient.callascurrentuser.md) | | Calls specified endpoint with provided clientParams on behalf of the user initiated request to the Kibana server (via HTTP request headers). See [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md). | +| [callAsInternalUser(endpoint, clientParams, options)](./kibana-plugin-core-server.legacyscopedclusterclient.callasinternaluser.md) | | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md). | + diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index 74422c82fc9ea7..f73595ea0a8ffa 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -17,18 +17,18 @@ The plugin integrates with the core system via lifecycle events: `setup` | Class | Description | | --- | --- | | [BasePath](./kibana-plugin-core-server.basepath.md) | Access or manipulate the Kibana base path | -| [ClusterClient](./kibana-plugin-core-server.clusterclient.md) | Represents an Elasticsearch cluster API client created by the platform. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [ClusterClient](./kibana-plugin-core-server.clusterclient.md). | | [CspConfig](./kibana-plugin-core-server.cspconfig.md) | CSP configuration for use in Kibana. | | [ElasticsearchConfig](./kibana-plugin-core-server.elasticsearchconfig.md) | Wrapper of config schema. | -| [ElasticsearchErrorHelpers](./kibana-plugin-core-server.elasticsearcherrorhelpers.md) | Helpers for working with errors returned from the Elasticsearch service.Since the internal data of errors are subject to change, consumers of the Elasticsearch service should always use these helpers to classify errors instead of checking error internals such as body.error.header[WWW-Authenticate] | | [KibanaRequest](./kibana-plugin-core-server.kibanarequest.md) | Kibana specific abstraction for an incoming request. | +| [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md) | | +| [LegacyElasticsearchErrorHelpers](./kibana-plugin-core-server.legacyelasticsearcherrorhelpers.md) | Helpers for working with errors returned from the Elasticsearch service.Since the internal data of errors are subject to change, consumers of the Elasticsearch service should always use these helpers to classify errors instead of checking error internals such as body.error.header[WWW-Authenticate] | +| [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md) | | | [RouteValidationError](./kibana-plugin-core-server.routevalidationerror.md) | Error to return when the validation is not successful. | | [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) | | | [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) | | | [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) | | | [SavedObjectsSerializer](./kibana-plugin-core-server.savedobjectsserializer.md) | A serializer that can be used to manually convert [raw](./kibana-plugin-core-server.savedobjectsrawdoc.md) or [sanitized](./kibana-plugin-core-server.savedobjectsanitizeddoc.md) documents to the other kind. | | [SavedObjectTypeRegistry](./kibana-plugin-core-server.savedobjecttyperegistry.md) | Registry holding information about all the registered [saved object types](./kibana-plugin-core-server.savedobjectstype.md). | -| [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md) | Serves the same purpose as "normal" ClusterClient but exposes additional callAsCurrentUser method that doesn't use credentials of the Kibana internal user (as callAsInternalUser does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.See [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md). | ## Enumerations @@ -54,7 +54,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | Interface | Description | | --- | --- | -| [APICaller](./kibana-plugin-core-server.apicaller.md) | | | [AssistanceAPIResponse](./kibana-plugin-core-server.assistanceapiresponse.md) | | | [AssistantAPIClientParams](./kibana-plugin-core-server.assistantapiclientparams.md) | | | [Authenticated](./kibana-plugin-core-server.authenticated.md) | | @@ -63,7 +62,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AuthRedirectedParams](./kibana-plugin-core-server.authredirectedparams.md) | Result of auth redirection. | | [AuthResultParams](./kibana-plugin-core-server.authresultparams.md) | Result of successful authentication. | | [AuthToolkit](./kibana-plugin-core-server.authtoolkit.md) | A tool set defining an outcome of Auth interceptor for incoming request. | -| [CallAPIOptions](./kibana-plugin-core-server.callapioptions.md) | The set of options that defines how API call should be made and result be processed. | | [Capabilities](./kibana-plugin-core-server.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | | [CapabilitiesSetup](./kibana-plugin-core-server.capabilitiessetup.md) | APIs to manage the [Capabilities](./kibana-plugin-core-server.capabilities.md) that will be used by the application.Plugins relying on capabilities to toggle some of their features should register them during the setup phase using the registerProvider method.Plugins having the responsibility to restrict capabilities depending on a given context should register their capabilities switcher using the registerSwitcher method.Refers to the methods documentation for complete description and examples. | | [CapabilitiesStart](./kibana-plugin-core-server.capabilitiesstart.md) | APIs to access the application [Capabilities](./kibana-plugin-core-server.capabilities.md). | @@ -78,7 +76,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [DeprecationInfo](./kibana-plugin-core-server.deprecationinfo.md) | | | [DeprecationSettings](./kibana-plugin-core-server.deprecationsettings.md) | UiSettings deprecation field options. | | [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) | Small container object used to expose information about discovered plugins that may or may not have been started. | -| [ElasticsearchError](./kibana-plugin-core-server.elasticsearcherror.md) | | | [ElasticsearchServiceSetup](./kibana-plugin-core-server.elasticsearchservicesetup.md) | | | [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) | | | [ElasticsearchStatusMeta](./kibana-plugin-core-server.elasticsearchstatusmeta.md) | | @@ -104,6 +101,9 @@ The plugin integrates with the core system via lifecycle events: `setup` | [IUiSettingsClient](./kibana-plugin-core-server.iuisettingsclient.md) | Server-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. | | [KibanaRequestEvents](./kibana-plugin-core-server.kibanarequestevents.md) | Request events. | | [KibanaRequestRoute](./kibana-plugin-core-server.kibanarequestroute.md) | Request specific route information exposed to a handler. | +| [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md) | | +| [LegacyCallAPIOptions](./kibana-plugin-core-server.legacycallapioptions.md) | The set of options that defines how API call should be made and result be processed. | +| [LegacyElasticsearchError](./kibana-plugin-core-server.legacyelasticsearcherror.md) | | | [LegacyRequest](./kibana-plugin-core-server.legacyrequest.md) | | | [LegacyServiceSetupDeps](./kibana-plugin-core-server.legacyservicesetupdeps.md) | | | [LegacyServiceStartDeps](./kibana-plugin-core-server.legacyservicestartdeps.md) | | @@ -128,7 +128,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [PluginConfigDescriptor](./kibana-plugin-core-server.pluginconfigdescriptor.md) | Describes a plugin configuration properties. | | [PluginInitializerContext](./kibana-plugin-core-server.plugininitializercontext.md) | Context that's available to plugins during initialization stage. | | [PluginManifest](./kibana-plugin-core-server.pluginmanifest.md) | Describes the set of required and optional properties plugin can define in its mandatory JSON manifest file. | -| [RequestHandlerContext](./kibana-plugin-core-server.requesthandlercontext.md) | Plugin specific context passed to a route handler.Provides the following clients and services: - [savedObjects.client](./kibana-plugin-core-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [savedObjects.typeRegistry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) - Type registry containing all the registered types. - [elasticsearch.legacy.client](./kibana-plugin-core-server.scopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-core-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request | +| [RequestHandlerContext](./kibana-plugin-core-server.requesthandlercontext.md) | Plugin specific context passed to a route handler.Provides the following clients and services: - [savedObjects.client](./kibana-plugin-core-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [savedObjects.typeRegistry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) - Type registry containing all the registered types. - [elasticsearch.legacy.client](./kibana-plugin-core-server.legacyscopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-core-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request | | [RouteConfig](./kibana-plugin-core-server.routeconfig.md) | Route specific configuration. | | [RouteConfigOptions](./kibana-plugin-core-server.routeconfigoptions.md) | Additional route options. | | [RouteConfigOptionsBody](./kibana-plugin-core-server.routeconfigoptionsbody.md) | Additional body options for a route | @@ -222,7 +222,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ConfigDeprecationProvider](./kibana-plugin-core-server.configdeprecationprovider.md) | A provider that should returns a list of [ConfigDeprecation](./kibana-plugin-core-server.configdeprecation.md).See [ConfigDeprecationFactory](./kibana-plugin-core-server.configdeprecationfactory.md) for more usage examples. | | [ConfigPath](./kibana-plugin-core-server.configpath.md) | | | [DestructiveRouteMethod](./kibana-plugin-core-server.destructiveroutemethod.md) | Set of HTTP methods changing the state of the server. | -| [ElasticsearchClientConfig](./kibana-plugin-core-server.elasticsearchclientconfig.md) | | | [Freezable](./kibana-plugin-core-server.freezable.md) | | | [GetAuthHeaders](./kibana-plugin-core-server.getauthheaders.md) | Get headers to authenticate a user against Elasticsearch. | | [GetAuthState](./kibana-plugin-core-server.getauthstate.md) | Gets authentication state for a request. Returned by auth interceptor. | @@ -234,16 +233,17 @@ The plugin integrates with the core system via lifecycle events: `setup` | [HttpResourcesResponseOptions](./kibana-plugin-core-server.httpresourcesresponseoptions.md) | HTTP Resources response parameters | | [HttpResponsePayload](./kibana-plugin-core-server.httpresponsepayload.md) | Data send to the client as a response payload. | | [IBasePath](./kibana-plugin-core-server.ibasepath.md) | Access or manipulate the Kibana base path[BasePath](./kibana-plugin-core-server.basepath.md) | -| [IClusterClient](./kibana-plugin-core-server.iclusterclient.md) | Represents an Elasticsearch cluster API client created by the platform. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [ClusterClient](./kibana-plugin-core-server.clusterclient.md). | | [IContextProvider](./kibana-plugin-core-server.icontextprovider.md) | A function that returns a context value for a specific key of given context type. | -| [ICustomClusterClient](./kibana-plugin-core-server.icustomclusterclient.md) | Represents an Elasticsearch cluster API client created by a plugin. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [ClusterClient](./kibana-plugin-core-server.clusterclient.md). | +| [ILegacyClusterClient](./kibana-plugin-core-server.ilegacyclusterclient.md) | Represents an Elasticsearch cluster API client created by the platform. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md). | +| [ILegacyCustomClusterClient](./kibana-plugin-core-server.ilegacycustomclusterclient.md) | Represents an Elasticsearch cluster API client created by a plugin. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [LegacyClusterClient](./kibana-plugin-core-server.legacyclusterclient.md). | +| [ILegacyScopedClusterClient](./kibana-plugin-core-server.ilegacyscopedclusterclient.md) | Serves the same purpose as "normal" ClusterClient but exposes additional callAsCurrentUser method that doesn't use credentials of the Kibana internal user (as callAsInternalUser does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.See [LegacyScopedClusterClient](./kibana-plugin-core-server.legacyscopedclusterclient.md). | | [IsAuthenticated](./kibana-plugin-core-server.isauthenticated.md) | Returns authentication status for a request. | | [ISavedObjectsRepository](./kibana-plugin-core-server.isavedobjectsrepository.md) | See [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) | | [ISavedObjectTypeRegistry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) | See [SavedObjectTypeRegistry](./kibana-plugin-core-server.savedobjecttyperegistry.md) for documentation. | -| [IScopedClusterClient](./kibana-plugin-core-server.iscopedclusterclient.md) | Serves the same purpose as "normal" ClusterClient but exposes additional callAsCurrentUser method that doesn't use credentials of the Kibana internal user (as callAsInternalUser does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.See [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md). | | [KibanaRequestRouteOptions](./kibana-plugin-core-server.kibanarequestrouteoptions.md) | Route options: If 'GET' or 'OPTIONS' method, body options won't be returned. | | [KibanaResponseFactory](./kibana-plugin-core-server.kibanaresponsefactory.md) | Creates an object containing request response payload, HTTP headers, error details, and other data transmitted to the client. | | [KnownHeaders](./kibana-plugin-core-server.knownheaders.md) | Set of well-known HTTP headers. | +| [LegacyElasticsearchClientConfig](./kibana-plugin-core-server.legacyelasticsearchclientconfig.md) | | | [LifecycleResponseFactory](./kibana-plugin-core-server.lifecycleresponsefactory.md) | Creates an object containing redirection or error response with error details, HTTP headers, and other data transmitted to the client. | | [LoggerConfigType](./kibana-plugin-core-server.loggerconfigtype.md) | | | [MIGRATION\_ASSISTANCE\_INDEX\_ACTION](./kibana-plugin-core-server.migration_assistance_index_action.md) | | @@ -257,7 +257,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [PluginName](./kibana-plugin-core-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. | | [PluginOpaqueId](./kibana-plugin-core-server.pluginopaqueid.md) | | | [PublicUiSettingsParams](./kibana-plugin-core-server.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) exposed to the client-side. | -| [RecursiveReadonly](./kibana-plugin-core-server.recursivereadonly.md) | | | [RedirectResponseOptions](./kibana-plugin-core-server.redirectresponseoptions.md) | HTTP response parameters for redirection response | | [RequestHandler](./kibana-plugin-core-server.requesthandler.md) | A function executed when route path matched requested resource path. Request handler is expected to return a result of one of [KibanaResponseFactory](./kibana-plugin-core-server.kibanaresponsefactory.md) functions. | | [RequestHandlerContextContainer](./kibana-plugin-core-server.requesthandlercontextcontainer.md) | An object that handles registration of http request context providers. | diff --git a/docs/development/core/server/kibana-plugin-core-server.recursivereadonly.md b/docs/development/core/server/kibana-plugin-core-server.recursivereadonly.md deleted file mode 100644 index bc9cd4680b17d1..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.recursivereadonly.md +++ /dev/null @@ -1,14 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [RecursiveReadonly](./kibana-plugin-core-server.recursivereadonly.md) - -## RecursiveReadonly type - - -Signature: - -```typescript -export declare 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/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md index 7b887d6d421e4c..b09fb121b8a632 100644 --- a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md +++ b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md @@ -14,7 +14,7 @@ core: { }; elasticsearch: { legacy: { - client: IScopedClusterClient; + client: ILegacyScopedClusterClient; }; }; uiSettings: { diff --git a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md index 99be0676bcda3d..55d6e931ac1584 100644 --- a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md +++ b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md @@ -6,7 +6,7 @@ Plugin specific context passed to a route handler. -Provides the following clients and services: - [savedObjects.client](./kibana-plugin-core-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [savedObjects.typeRegistry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) - Type registry containing all the registered types. - [elasticsearch.legacy.client](./kibana-plugin-core-server.scopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-core-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request +Provides the following clients and services: - [savedObjects.client](./kibana-plugin-core-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [savedObjects.typeRegistry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) - Type registry containing all the registered types. - [elasticsearch.legacy.client](./kibana-plugin-core-server.legacyscopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-core-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request Signature: @@ -18,5 +18,5 @@ export interface RequestHandlerContext | Property | Type | Description | | --- | --- | --- | -| [core](./kibana-plugin-core-server.requesthandlercontext.core.md) | {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
};
elasticsearch: {
legacy: {
client: IScopedClusterClient;
};
};
uiSettings: {
client: IUiSettingsClient;
};
} | | +| [core](./kibana-plugin-core-server.requesthandlercontext.core.md) | {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
};
elasticsearch: {
legacy: {
client: ILegacyScopedClusterClient;
};
};
uiSettings: {
client: IUiSettingsClient;
};
} | | diff --git a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient._constructor_.md b/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient._constructor_.md deleted file mode 100644 index d4d1d442a57f98..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient._constructor_.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md) > [(constructor)](./kibana-plugin-core-server.scopedclusterclient._constructor_.md) - -## ScopedClusterClient.(constructor) - -Constructs a new instance of the `ScopedClusterClient` class - -Signature: - -```typescript -constructor(internalAPICaller: APICaller, scopedAPICaller: APICaller, headers?: Headers | undefined); -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| internalAPICaller | APICaller | | -| scopedAPICaller | APICaller | | -| headers | Headers | undefined | | - diff --git a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.md b/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.md deleted file mode 100644 index 058d65b587dbed..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.scopedclusterclient.md +++ /dev/null @@ -1,29 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md) - -## ScopedClusterClient class - -Serves the same purpose as "normal" `ClusterClient` but exposes additional `callAsCurrentUser` method that doesn't use credentials of the Kibana internal user (as `callAsInternalUser` does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API. - -See [ScopedClusterClient](./kibana-plugin-core-server.scopedclusterclient.md). - -Signature: - -```typescript -export declare class ScopedClusterClient implements IScopedClusterClient -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(internalAPICaller, scopedAPICaller, headers)](./kibana-plugin-core-server.scopedclusterclient._constructor_.md) | | Constructs a new instance of the ScopedClusterClient class | - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [callAsCurrentUser(endpoint, clientParams, options)](./kibana-plugin-core-server.scopedclusterclient.callascurrentuser.md) | | Calls specified endpoint with provided clientParams on behalf of the user initiated request to the Kibana server (via HTTP request headers). See [APICaller](./kibana-plugin-core-server.apicaller.md). | -| [callAsInternalUser(endpoint, clientParams, options)](./kibana-plugin-core-server.scopedclusterclient.callasinternaluser.md) | | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-core-server.apicaller.md). | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md index 85eb4825bc2e32..a25f4a0c373b2c 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md @@ -7,5 +7,5 @@ Signature: ```typescript -QueryStringInput: React.FC> +QueryStringInput: React.FC> ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.gettime.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.gettime.md new file mode 100644 index 00000000000000..54e7cf92f500cf --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.gettime.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [getTime](./kibana-plugin-plugins-data-server.gettime.md) + +## getTime() function + +Signature: + +```typescript +export declare function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, options?: { + forceNow?: Date; + fieldName?: string; +}): import("../..").RangeFilter | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| indexPattern | IIndexPattern | undefined | | +| timeRange | TimeRange | | +| options | {
forceNow?: Date;
fieldName?: string;
} | | + +Returns: + +`import("../..").RangeFilter | undefined` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher._constructor_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher._constructor_.md index f9bbcc5a356e13..d36ebd0745e8d0 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher._constructor_.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher._constructor_.md @@ -9,12 +9,12 @@ Constructs a new instance of the `IndexPatternsFetcher` class Signature: ```typescript -constructor(callDataCluster: APICaller); +constructor(callDataCluster: LegacyAPICaller); ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| callDataCluster | APICaller | | +| callDataCluster | LegacyAPICaller | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index f492ba2843a697..c80112fb17dde5 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -23,6 +23,7 @@ | Function | Description | | --- | --- | | [getDefaultSearchParams(config)](./kibana-plugin-plugins-data-server.getdefaultsearchparams.md) | | +| [getTime(indexPattern, timeRange, options)](./kibana-plugin-plugins-data-server.gettime.md) | | | [parseInterval(interval)](./kibana-plugin-plugins-data-server.parseinterval.md) | | | [plugin(initializerContext)](./kibana-plugin-plugins-data-server.plugin.md) | Static code to be shared externally | | [shouldReadFieldFromDocValues(aggregatable, esType)](./kibana-plugin-plugins-data-server.shouldreadfieldfromdocvalues.md) | | diff --git a/package.json b/package.json index b1202631a0c026..b520be4df69696 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,6 @@ "resolutions": { "**/@types/node": ">=10.17.17 <10.20.0", "**/@types/react": "^16.9.36", - "**/@types/react-router": "^5.1.3", "**/@types/hapi": "^17.0.18", "**/@types/angular": "^1.6.56", "**/@types/hoist-non-react-statics": "^3.3.1", @@ -202,6 +201,7 @@ "inline-style": "^2.0.0", "joi": "^13.5.2", "jquery": "^3.5.0", + "js-levenshtein": "^1.1.6", "js-yaml": "3.13.1", "json-stable-stringify": "^1.0.1", "json-stringify-pretty-compact": "1.2.0", @@ -245,8 +245,8 @@ "react-monaco-editor": "~0.27.0", "react-redux": "^7.2.0", "react-resize-detector": "^4.2.0", - "react-router": "^5.1.2", - "react-router-dom": "^5.1.2", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", "react-sizeme": "^2.3.6", "react-use": "^13.27.0", "reactcss": "1.2.3", @@ -361,6 +361,7 @@ "@types/markdown-it": "^0.0.7", "@types/minimatch": "^2.0.29", "@types/mocha": "^7.0.2", + "@types/mock-fs": "^4.10.0", "@types/moment-timezone": "^0.5.12", "@types/mustache": "^0.8.31", "@types/node": ">=10.17.17 <10.20.0", @@ -377,8 +378,8 @@ "@types/react-grid-layout": "^0.16.7", "@types/react-redux": "^7.1.9", "@types/react-resize-detector": "^4.0.1", - "@types/react-router": "^5.1.3", - "@types/react-router-dom": "^5.1.3", + "@types/react-router": "^5.1.7", + "@types/react-router-dom": "^5.1.5", "@types/react-virtualized": "^9.18.7", "@types/recompose": "^0.30.6", "@types/redux-actions": "^2.6.1", @@ -473,6 +474,7 @@ "listr": "^0.14.1", "load-grunt-config": "^3.0.1", "mocha": "^7.1.1", + "mock-fs": "^4.12.0", "mock-http-server": "1.3.0", "ms-chromium-edge-driver": "^0.2.3", "multistream": "^2.1.1", diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/kibana.json rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/server/index.ts similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/index.ts rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/server/index.ts diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/lib.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/server/lib.ts similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/lib.ts rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/server/lib.ts diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index 2265bad9f6afaf..b6b0973f0d5398 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -43,18 +43,18 @@ OptimizerConfig { "id": "bar", "isUiPlugin": true, }, - Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/baz, - "extraPublicDirs": Array [], - "id": "baz", - "isUiPlugin": false, - }, Object { "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, "extraPublicDirs": Array [], "id": "foo", "isUiPlugin": true, }, + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/nested/baz, + "extraPublicDirs": Array [], + "id": "baz", + "isUiPlugin": false, + }, ], "profileWebpack": false, "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts index 0961881df461c5..f7b457ca42c6dc 100644 --- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts +++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts @@ -41,18 +41,18 @@ it('parses kibana.json files of plugins found in pluginDirs', () => { "id": "bar", "isUiPlugin": true, }, - Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz, - "extraPublicDirs": Array [], - "id": "baz", - "isUiPlugin": false, - }, Object { "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo, "extraPublicDirs": Array [], "id": "foo", "isUiPlugin": true, }, + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz, + "extraPublicDirs": Array [], + "id": "baz", + "isUiPlugin": false, + }, Object { "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz, "extraPublicDirs": Array [], diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts index bfc60a29efa27d..83637691004f40 100644 --- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts +++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts @@ -37,7 +37,7 @@ export function findKibanaPlatformPlugins(scanDirs: string[], paths: string[]) { .sync( Array.from( new Set([ - ...scanDirs.map((dir) => `${dir}/*/kibana.json`), + ...scanDirs.map(nestedScanDirPaths).reduce((dirs, current) => [...dirs, ...current], []), ...paths.map((path) => `${path}/kibana.json`), ]) ), @@ -51,6 +51,17 @@ export function findKibanaPlatformPlugins(scanDirs: string[], paths: string[]) { ); } +function nestedScanDirPaths(dir: string): string[] { + // down to 5 level max + return [ + `${dir}/*/kibana.json`, + `${dir}/*/*/kibana.json`, + `${dir}/*/*/*/kibana.json`, + `${dir}/*/*/*/*/kibana.json`, + `${dir}/*/*/*/*/*/kibana.json`, + ]; +} + function readKibanaPlatformPlugin(manifestPath: string): KibanaPlatformPlugin { if (!Path.isAbsolute(manifestPath)) { throw new TypeError('expected new platform manifest path to be absolute'); diff --git a/packages/kbn-ui-shared-deps/entry.js b/packages/kbn-ui-shared-deps/entry.js index 88e84fc87ae533..aaa46ab74714f1 100644 --- a/packages/kbn-ui-shared-deps/entry.js +++ b/packages/kbn-ui-shared-deps/entry.js @@ -38,6 +38,7 @@ export const ReactDomServer = require('react-dom/server'); export const ReactIntl = require('react-intl'); export const ReactRouter = require('react-router'); // eslint-disable-line export const ReactRouterDom = require('react-router-dom'); +export const StyledComponents = require('styled-components'); Moment.tz.load(require('moment-timezone/data/packed/latest.json')); diff --git a/packages/kbn-ui-shared-deps/index.js b/packages/kbn-ui-shared-deps/index.js index 301d1765558479..596c31820e80d0 100644 --- a/packages/kbn-ui-shared-deps/index.js +++ b/packages/kbn-ui-shared-deps/index.js @@ -42,6 +42,7 @@ exports.externals = { 'react-intl': '__kbnSharedDeps__.ReactIntl', 'react-router': '__kbnSharedDeps__.ReactRouter', 'react-router-dom': '__kbnSharedDeps__.ReactRouterDom', + 'styled-components': '__kbnSharedDeps__.StyledComponents', '@kbn/monaco': '__kbnSharedDeps__.KbnMonaco', // this is how plugins/consumers from npm load monaco 'monaco-editor/esm/vs/editor/editor.api': '__kbnSharedDeps__.MonacoBarePluginApi', diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 1cc04afad56696..0e3bb235c3d9f5 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -26,20 +26,22 @@ "react": "^16.12.0", "react-dom": "^16.12.0", "react-intl": "^2.8.0", - "react-router": "^5.1.2", - "react-router-dom": "^5.1.2", + "react-is": "^16.8.0", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", "regenerator-runtime": "^0.13.3", "rxjs": "^6.5.5", + "styled-components": "^5.1.0", "symbol-observable": "^1.2.0", "whatwg-fetch": "^3.0.0" }, "devDependencies": { "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", - "loader-utils": "^1.2.3", - "val-loader": "^1.1.1", "css-loader": "^3.4.2", "del": "^5.1.0", + "loader-utils": "^1.2.3", + "val-loader": "^1.1.1", "webpack": "^4.41.5" } } diff --git a/packages/kbn-utility-types/index.ts b/packages/kbn-utility-types/index.ts index 9a8a81460f410e..6ccfeb8ab052c9 100644 --- a/packages/kbn-utility-types/index.ts +++ b/packages/kbn-utility-types/index.ts @@ -61,7 +61,8 @@ 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 interface RecursiveReadonlyArray extends ReadonlyArray> {} + export type RecursiveReadonly = T extends (...args: any) => any ? T : T extends any[] diff --git a/renovate.json5 b/renovate.json5 index 1af155fcc645ec..49a255d60f29e7 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -636,6 +636,14 @@ '(\\b|_)mocha(\\b|_)', ], }, + { + groupSlug: 'mock-fs', + groupName: 'mock-fs related packages', + packageNames: [ + 'mock-fs', + '@types/mock-fs', + ], + }, { groupSlug: 'moment', groupName: 'moment related packages', diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index 09f9bb2333dbe9..6db6199b391e14 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -266,6 +266,11 @@ export class ClusterManager { fromRoot('x-pack/plugins/apm/e2e'), fromRoot('x-pack/plugins/apm/scripts'), fromRoot('x-pack/plugins/canvas/canvas_plugin_src'), // prevents server from restarting twice for Canvas plugin changes, + fromRoot('x-pack/plugins/case/server/scripts'), + fromRoot('x-pack/plugins/lists/scripts'), + fromRoot('x-pack/plugins/lists/server/scripts'), + fromRoot('x-pack/plugins/security_solution/scripts'), + fromRoot('x-pack/plugins/security_solution/server/lib/detection_engine/scripts'), 'plugins/java_languageserver', ]; diff --git a/src/core/public/application/capabilities/capabilities_service.test.ts b/src/core/public/application/capabilities/capabilities_service.test.ts index dfbb449b4d58e6..286a93fdc23988 100644 --- a/src/core/public/application/capabilities/capabilities_service.test.ts +++ b/src/core/public/application/capabilities/capabilities_service.test.ts @@ -48,7 +48,7 @@ describe('#start', () => { appIds: ['app1', 'app2', 'legacyApp1', 'legacyApp2'], }); - // @ts-ignore TypeScript knows this shouldn't be possible + // @ts-expect-error TypeScript knows this shouldn't be possible expect(() => (capabilities.foo = 'foo')).toThrowError(); }); @@ -59,7 +59,7 @@ describe('#start', () => { appIds: ['app1', 'app2', 'legacyApp1', 'legacyApp2'], }); - // @ts-ignore TypeScript knows this shouldn't be possible + // @ts-expect-error TypeScript knows this shouldn't be possible expect(() => (capabilities.foo = 'foo')).toThrowError(); }); }); diff --git a/src/core/public/application/capabilities/capabilities_service.tsx b/src/core/public/application/capabilities/capabilities_service.tsx index d602422c146348..7304a8e5a66bc1 100644 --- a/src/core/public/application/capabilities/capabilities_service.tsx +++ b/src/core/public/application/capabilities/capabilities_service.tsx @@ -16,9 +16,10 @@ * specific language governing permissions and limitations * under the License. */ +import { RecursiveReadonly } from '@kbn/utility-types'; import { Capabilities } from '../../../types/capabilities'; -import { deepFreeze, RecursiveReadonly } from '../../../utils'; +import { deepFreeze } from '../../../utils'; import { HttpStart } from '../../http'; interface StartDeps { diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 6926b6acf24115..0fe97431b15690 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -19,6 +19,7 @@ import { Observable } from 'rxjs'; import { History } from 'history'; +import { RecursiveReadonly } from '@kbn/utility-types'; import { Capabilities } from './capabilities'; import { ChromeStart } from '../chrome'; @@ -30,7 +31,6 @@ import { NotificationsStart } from '../notifications'; import { OverlayStart } from '../overlays'; import { PluginOpaqueId } from '../plugins'; import { IUiSettingsClient } from '../ui_settings'; -import { RecursiveReadonly } from '../../utils'; import { SavedObjectsStart } from '../saved_objects'; import { AppCategory } from '../../types'; import { ScopedHistory } from './scoped_history'; @@ -269,6 +269,10 @@ export interface LegacyApp extends AppBase { */ export type PublicAppInfo = Omit & { legacy: false; + // remove optional on fields populated with default values + status: AppStatus; + navLinkStatus: AppNavLinkStatus; + appRoute: string; }; /** @@ -278,6 +282,9 @@ export type PublicAppInfo = Omit & { */ export type PublicLegacyAppInfo = Omit & { legacy: true; + // remove optional on fields populated with default values + status: AppStatus; + navLinkStatus: AppNavLinkStatus; }; /** diff --git a/src/core/public/application/utils.ts b/src/core/public/application/utils.ts index 1dc9ec70590017..92d25fa468c4a5 100644 --- a/src/core/public/application/utils.ts +++ b/src/core/public/application/utils.ts @@ -120,12 +120,17 @@ export function getAppInfo(app: App | LegacyApp): PublicAppInfo | Publi const { updater$, ...infos } = app; return { ...infos, + status: app.status!, + navLinkStatus: app.navLinkStatus!, legacy: true, }; } else { const { updater$, mount, ...infos } = app; return { ...infos, + status: app.status!, + navLinkStatus: app.navLinkStatus!, + appRoute: app.appRoute!, legacy: false, }; } diff --git a/src/core/public/chrome/recently_accessed/persisted_log.test.ts b/src/core/public/chrome/recently_accessed/persisted_log.test.ts index 9b307a2d25faf4..4229efdf7ca9dc 100644 --- a/src/core/public/chrome/recently_accessed/persisted_log.test.ts +++ b/src/core/public/chrome/recently_accessed/persisted_log.test.ts @@ -59,7 +59,7 @@ describe('PersistedLog', () => { describe('internal functionality', () => { test('reads from storage', () => { - // @ts-ignore + // @ts-expect-error const log = new PersistedLog(historyName, { maxLength: 10 }, storage); expect(storage.getItem).toHaveBeenCalledTimes(1); diff --git a/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts b/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts index 3c9713a93144a9..14c3c581f9f174 100644 --- a/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts +++ b/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts @@ -55,11 +55,11 @@ describe('RecentlyAccessed#start()', () => { let originalLocalStorage: Storage; beforeAll(() => { originalLocalStorage = window.localStorage; - // @ts-ignore + // @ts-expect-error window.localStorage = new LocalStorageMock(); }); beforeEach(() => localStorage.clear()); - // @ts-ignore + // @ts-expect-error afterAll(() => (window.localStorage = originalLocalStorage)); const getStart = async () => { diff --git a/src/core/public/chrome/ui/header/header_help_menu.tsx b/src/core/public/chrome/ui/header/header_help_menu.tsx index 1023a561a0fe33..6d2938e3345a65 100644 --- a/src/core/public/chrome/ui/header/header_help_menu.tsx +++ b/src/core/public/chrome/ui/header/header_help_menu.tsx @@ -312,7 +312,6 @@ class HeaderHelpMenuUI extends Component { ); return ( - // @ts-ignore repositionOnScroll doesn't exist in EuiPopover { fetchMock.get('*', {}); await expect( fetchInstance.fetch( - // @ts-ignore + // @ts-expect-error { path: '/', headers: { hello: 'world' } }, { headers: { hello: 'mars' } } ) diff --git a/src/core/public/http/http_service.test.ts b/src/core/public/http/http_service.test.ts index 78220af9cc83b5..0afea5aaa506a2 100644 --- a/src/core/public/http/http_service.test.ts +++ b/src/core/public/http/http_service.test.ts @@ -17,7 +17,7 @@ * under the License. */ -// @ts-ignore +// @ts-expect-error import fetchMock from 'fetch-mock/es5/client'; import { loadingServiceMock } from './http_service.test.mocks'; diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 41af0f1b8395fe..3e4e70fb99508e 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -81,7 +81,6 @@ import { export { CoreContext, CoreSystem } from './core_system'; export { - RecursiveReadonly, DEFAULT_APP_CATEGORIES, getFlattenedObject, URLMeaningfulParts, diff --git a/src/core/public/injected_metadata/injected_metadata_service.test.ts b/src/core/public/injected_metadata/injected_metadata_service.test.ts index cf4b72114d5ac2..1a8b4d14ee2490 100644 --- a/src/core/public/injected_metadata/injected_metadata_service.test.ts +++ b/src/core/public/injected_metadata/injected_metadata_service.test.ts @@ -58,7 +58,6 @@ describe('setup.getCspConfig()', () => { const csp = injectedMetadata.setup().getCspConfig(); expect(() => { - // @ts-ignore TS knows this shouldn't be possible csp.warnLegacyBrowsers = false; }).toThrowError(); }); @@ -100,11 +99,11 @@ describe('setup.getPlugins()', () => { plugins.push({ id: 'new-plugin', plugin: {} as DiscoveredPlugin }); }).toThrowError(); expect(() => { - // @ts-ignore TS knows this shouldn't be possible + // @ts-expect-error TS knows this shouldn't be possible plugins[0].name = 'changed'; }).toThrowError(); expect(() => { - // @ts-ignore TS knows this shouldn't be possible + // @ts-expect-error TS knows this shouldn't be possible plugins[0].newProp = 'changed'; }).toThrowError(); }); @@ -136,7 +135,7 @@ describe('setup.getLegacyMetadata()', () => { foo: true, }); expect(() => { - // @ts-ignore TS knows this shouldn't be possible + // @ts-expect-error TS knows this shouldn't be possible legacyMetadata.foo = false; }).toThrowError(); }); diff --git a/src/core/public/integrations/styles/styles_service.ts b/src/core/public/integrations/styles/styles_service.ts index 41fc861d6cb39a..d1d7f2170fde39 100644 --- a/src/core/public/integrations/styles/styles_service.ts +++ b/src/core/public/integrations/styles/styles_service.ts @@ -21,7 +21,7 @@ import { Subscription } from 'rxjs'; import { IUiSettingsClient } from '../../ui_settings'; import { CoreService } from '../../../types'; -// @ts-ignore +// @ts-expect-error import disableAnimationsCss from '!!raw-loader!./disable_animations.css'; interface StartDeps { diff --git a/src/core/public/kbn_bootstrap.ts b/src/core/public/kbn_bootstrap.ts index 0f860618167018..a108b5aaa47ec0 100644 --- a/src/core/public/kbn_bootstrap.ts +++ b/src/core/public/kbn_bootstrap.ts @@ -42,7 +42,6 @@ export function __kbnBootstrap__() { const APM_ENABLED = process.env.IS_KIBANA_DISTRIBUTABLE !== 'true' && apmConfig != null; if (APM_ENABLED) { - // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-var-requires const { init, apm } = require('@elastic/apm-rum'); if (apmConfig.globalLabels) { diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index d10e351f4d13ed..86e281a49b744a 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -116,6 +116,7 @@ import { PublicUiSettingsParams as PublicUiSettingsParams_2 } from 'src/core/ser import { PutScriptParams } from 'elasticsearch'; import { PutTemplateParams } from 'elasticsearch'; import React from 'react'; +import { RecursiveReadonly } from '@kbn/utility-types'; import { ReindexParams } from 'elasticsearch'; import { ReindexRethrottleParams } from 'elasticsearch'; import { RenderSearchTemplateParams } from 'elasticsearch'; @@ -1143,23 +1144,21 @@ export type PluginOpaqueId = symbol; // @public export type PublicAppInfo = Omit & { legacy: false; + status: AppStatus; + navLinkStatus: AppNavLinkStatus; + appRoute: string; }; // @public export type PublicLegacyAppInfo = Omit & { legacy: true; + status: AppStatus; + navLinkStatus: AppNavLinkStatus; }; // @public export type PublicUiSettingsParams = Omit; -// Warning: (ae-forgotten-export) The symbol "RecursiveReadonlyArray" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export type RecursiveReadonly = T extends (...args: any[]) => any ? T : T extends any[] ? RecursiveReadonlyArray : T extends object ? Readonly<{ - [K in keyof T]: RecursiveReadonly; -}> : T; - // Warning: (ae-missing-release-tag) "SavedObject" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/src/core/public/saved_objects/saved_objects_client.test.ts b/src/core/public/saved_objects/saved_objects_client.test.ts index 0c34a16c68e99d..20824af38af0f6 100644 --- a/src/core/public/saved_objects/saved_objects_client.test.ts +++ b/src/core/public/saved_objects/saved_objects_client.test.ts @@ -432,7 +432,7 @@ describe('SavedObjectsClient', () => { sortOrder: 'sort', // Not currently supported by API }; - // @ts-ignore + // @ts-expect-error savedObjectsClient.find(options); expect(http.fetch.mock.calls).toMatchInlineSnapshot(` Array [ diff --git a/src/core/public/ui_settings/ui_settings_api.test.ts b/src/core/public/ui_settings/ui_settings_api.test.ts index bab7081509d53e..14791407d25508 100644 --- a/src/core/public/ui_settings/ui_settings_api.test.ts +++ b/src/core/public/ui_settings/ui_settings_api.test.ts @@ -17,7 +17,7 @@ * under the License. */ -// @ts-ignore +// @ts-expect-error import fetchMock from 'fetch-mock/es5/client'; import * as Rx from 'rxjs'; import { takeUntil, toArray } from 'rxjs/operators'; diff --git a/src/core/server/elasticsearch/__snapshots__/elasticsearch_config.test.ts.snap b/src/core/server/elasticsearch/__snapshots__/elasticsearch_config.test.ts.snap deleted file mode 100644 index 75627f311d9a58..00000000000000 --- a/src/core/server/elasticsearch/__snapshots__/elasticsearch_config.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`#username throws if equal to "elastic", only while running from source 1`] = `"[username]: value of \\"elastic\\" is forbidden. This is a superuser account that can obfuscate privilege-related issues. You should use the \\"kibana_system\\" user instead."`; diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts index ccd5fd0c7a5718..648eaaf8a97f27 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -367,6 +367,8 @@ test('#username throws if equal to "elastic", only while running from source', ( const obj = { username: 'elastic', }; - expect(() => config.schema.validate(obj, { dist: false })).toThrowErrorMatchingSnapshot(); + expect(() => config.schema.validate(obj, { dist: false })).toThrowErrorMatchingInlineSnapshot( + `"[username]: value of \\"elastic\\" is forbidden. This is a superuser account that can obfuscate privilege-related issues. You should use the \\"kibana_system\\" user instead."` + ); expect(() => config.schema.validate(obj, { dist: true })).not.toThrow(); }); diff --git a/src/core/server/elasticsearch/elasticsearch_service.mock.ts b/src/core/server/elasticsearch/elasticsearch_service.mock.ts index 55e60f5987604e..fdfc48fa9f754b 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.mock.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.mock.ts @@ -19,26 +19,29 @@ import { BehaviorSubject } from 'rxjs'; import { Client } from 'elasticsearch'; -import { IClusterClient, ICustomClusterClient } from './cluster_client'; -import { IScopedClusterClient } from './scoped_cluster_client'; +import { + ILegacyClusterClient, + ILegacyCustomClusterClient, + ILegacyScopedClusterClient, +} from './legacy'; import { ElasticsearchConfig } from './elasticsearch_config'; import { ElasticsearchService } from './elasticsearch_service'; import { InternalElasticsearchServiceSetup, ElasticsearchStatusMeta } from './types'; import { NodesVersionCompatibility } from './version_check/ensure_es_version'; import { ServiceStatus, ServiceStatusLevels } from '../status'; -const createScopedClusterClientMock = (): jest.Mocked => ({ +const createScopedClusterClientMock = (): jest.Mocked => ({ callAsInternalUser: jest.fn(), callAsCurrentUser: jest.fn(), }); -const createCustomClusterClientMock = (): jest.Mocked => ({ +const createCustomClusterClientMock = (): jest.Mocked => ({ ...createClusterClientMock(), close: jest.fn(), }); function createClusterClientMock() { - const client: jest.Mocked = { + const client: jest.Mocked = { callAsInternalUser: jest.fn(), asScoped: jest.fn(), }; @@ -48,8 +51,8 @@ function createClusterClientMock() { interface MockedElasticSearchServiceSetup { legacy: { - createClient: jest.Mock; - client: jest.Mocked; + createClient: jest.Mock; + client: jest.Mocked; }; } @@ -81,7 +84,7 @@ const createStartContractMock = () => { type MockedInternalElasticSearchServiceSetup = jest.Mocked< InternalElasticsearchServiceSetup & { - legacy: { client: jest.Mocked }; + legacy: { client: jest.Mocked }; } >; const createInternalSetupContractMock = () => { diff --git a/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts b/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts index e87913a3c5e4ff..c30230a7847a0e 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts @@ -18,4 +18,4 @@ */ export const MockClusterClient = jest.fn(); -jest.mock('./cluster_client', () => ({ ClusterClient: MockClusterClient })); +jest.mock('./legacy/cluster_client', () => ({ LegacyClusterClient: MockClusterClient })); diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index 26001bf83924fb..f47b33dd410f6c 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -34,23 +34,26 @@ import { merge } from '../../utils'; import { CoreContext } from '../core_context'; import { Logger } from '../logging'; import { - ClusterClient, - ScopeableRequest, - IClusterClient, - ICustomClusterClient, -} from './cluster_client'; -import { ElasticsearchClientConfig } from './elasticsearch_client_config'; + LegacyClusterClient, + ILegacyClusterClient, + ILegacyCustomClusterClient, + LegacyElasticsearchClientConfig, + LegacyCallAPIOptions, +} from './legacy'; import { ElasticsearchConfig, ElasticsearchConfigType } from './elasticsearch_config'; import { InternalHttpServiceSetup, GetAuthHeaders } from '../http/'; -import { InternalElasticsearchServiceSetup, ElasticsearchServiceStart } from './types'; -import { CallAPIOptions } from './api_types'; +import { + InternalElasticsearchServiceSetup, + ElasticsearchServiceStart, + ScopeableRequest, +} from './types'; import { pollEsNodesVersion } from './version_check/ensure_es_version'; import { calculateStatus$ } from './status'; /** @internal */ interface CoreClusterClients { config: ElasticsearchConfig; - client: ClusterClient; + client: LegacyClusterClient; } interface SetupDeps { @@ -67,9 +70,9 @@ export class ElasticsearchService private kibanaVersion: string; private createClient?: ( type: string, - clientConfig?: Partial - ) => ICustomClusterClient; - private client?: IClusterClient; + clientConfig?: Partial + ) => ILegacyCustomClusterClient; + private client?: ILegacyClusterClient; constructor(private readonly coreContext: CoreContext) { this.kibanaVersion = coreContext.env.packageInfo.version; @@ -123,7 +126,7 @@ export class ElasticsearchService async callAsInternalUser( endpoint: string, clientParams: Record = {}, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) { const _client = await client$.pipe(take(1)).toPromise(); return await _client.callAsInternalUser(endpoint, clientParams, options); @@ -134,7 +137,7 @@ export class ElasticsearchService async callAsCurrentUser( endpoint: string, clientParams: Record = {}, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) { const _client = await client$.pipe(take(1)).toPromise(); return await _client @@ -155,7 +158,10 @@ export class ElasticsearchService kibanaVersion: this.kibanaVersion, }).pipe(takeUntil(this.stop$), shareReplay({ refCount: true, bufferSize: 1 })); - this.createClient = (type: string, clientConfig: Partial = {}) => { + this.createClient = ( + type: string, + clientConfig: Partial = {} + ) => { const finalConfig = merge({}, config, clientConfig); return this.createClusterClient(type, finalConfig, deps.http.getAuthHeaders); }; @@ -193,10 +199,10 @@ export class ElasticsearchService private createClusterClient( type: string, - config: ElasticsearchClientConfig, + config: LegacyElasticsearchClientConfig, getAuthHeaders?: GetAuthHeaders ) { - return new ClusterClient( + return new LegacyClusterClient( config, this.coreContext.logger.get('elasticsearch', type), getAuthHeaders diff --git a/src/core/server/elasticsearch/index.ts b/src/core/server/elasticsearch/index.ts index 2e45f710c4dcfd..f5f5f5cc7b6f88 100644 --- a/src/core/server/elasticsearch/index.ts +++ b/src/core/server/elasticsearch/index.ts @@ -18,17 +18,14 @@ */ export { ElasticsearchService } from './elasticsearch_service'; +export { config, configSchema, ElasticsearchConfig } from './elasticsearch_config'; +export { NodesVersionCompatibility } from './version_check/ensure_es_version'; export { - ClusterClient, + ElasticsearchServiceSetup, + ElasticsearchServiceStart, + ElasticsearchStatusMeta, + InternalElasticsearchServiceSetup, FakeRequest, - IClusterClient, - ICustomClusterClient, ScopeableRequest, -} from './cluster_client'; -export { IScopedClusterClient, ScopedClusterClient, Headers } from './scoped_cluster_client'; -export { ElasticsearchClientConfig } from './elasticsearch_client_config'; -export { config, configSchema, ElasticsearchConfig } from './elasticsearch_config'; -export { ElasticsearchError, ElasticsearchErrorHelpers } from './errors'; -export * from './api_types'; -export * from './types'; -export { NodesVersionCompatibility } from './version_check/ensure_es_version'; +} from './types'; +export * from './legacy'; diff --git a/src/core/server/elasticsearch/api_types.ts b/src/core/server/elasticsearch/legacy/api_types.ts similarity index 54% rename from src/core/server/elasticsearch/api_types.ts rename to src/core/server/elasticsearch/legacy/api_types.ts index 5f2b61eb4935fd..b9699ab290e3fc 100644 --- a/src/core/server/elasticsearch/api_types.ts +++ b/src/core/server/elasticsearch/legacy/api_types.ts @@ -151,7 +151,7 @@ import { * * @public */ -export interface CallAPIOptions { +export interface LegacyCallAPIOptions { /** * Indicates whether `401 Unauthorized` errors returned from the Elasticsearch API * should be wrapped into `Boom` error instances with properly set `WWW-Authenticate` @@ -166,154 +166,154 @@ export interface CallAPIOptions { } /** @public */ -export interface APICaller { +export interface LegacyAPICaller { /* eslint-disable */ - (endpoint: 'bulk', params: BulkIndexDocumentsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'clearScroll', params: ClearScrollParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'count', params: CountParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'create', params: CreateDocumentParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'delete', params: DeleteDocumentParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'deleteByQuery', params: DeleteDocumentByQueryParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'deleteScript', params: DeleteScriptParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'deleteTemplate', params: DeleteTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'exists', params: ExistsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'explain', params: ExplainParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'fieldStats', params: FieldStatsParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'bulk', params: BulkIndexDocumentsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'clearScroll', params: ClearScrollParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'count', params: CountParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'create', params: CreateDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'delete', params: DeleteDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'deleteByQuery', params: DeleteDocumentByQueryParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'deleteScript', params: DeleteScriptParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'deleteTemplate', params: DeleteTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'exists', params: ExistsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'explain', params: ExplainParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'fieldStats', params: FieldStatsParams, options?: LegacyCallAPIOptions): ReturnType; // Generic types cannot be properly looked up with ReturnType. Hard code these explicitly. - (endpoint: 'get', params: GetParams, options?: CallAPIOptions): Promise>; - (endpoint: 'getScript', params: GetScriptParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'getSource', params: GetSourceParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'getTemplate', params: GetTemplateParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'get', params: GetParams, options?: LegacyCallAPIOptions): Promise>; + (endpoint: 'getScript', params: GetScriptParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'getSource', params: GetSourceParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'getTemplate', params: GetTemplateParams, options?: LegacyCallAPIOptions): ReturnType; // Generic types cannot be properly looked up with ReturnType. Hard code these explicitly. - (endpoint: 'index', params: IndexDocumentParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'info', params: InfoParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'index', params: IndexDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'info', params: InfoParams, options?: LegacyCallAPIOptions): ReturnType; // Generic types cannot be properly looked up with ReturnType. Hard code these explicitly. - (endpoint: 'mget', params: MGetParams, options?: CallAPIOptions): Promise>; - (endpoint: 'msearch', params: MSearchParams, options?: CallAPIOptions): Promise>; - (endpoint: 'msearchTemplate', params: MSearchTemplateParams, options?: CallAPIOptions): Promise>; - (endpoint: 'mtermvectors', params: MTermVectorsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'ping', params: PingParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'putScript', params: PutScriptParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'putTemplate', params: PutTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'reindex', params: ReindexParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'reindexRethrottle', params: ReindexRethrottleParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'renderSearchTemplate', params: RenderSearchTemplateParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'mget', params: MGetParams, options?: LegacyCallAPIOptions): Promise>; + (endpoint: 'msearch', params: MSearchParams, options?: LegacyCallAPIOptions): Promise>; + (endpoint: 'msearchTemplate', params: MSearchTemplateParams, options?: LegacyCallAPIOptions): Promise>; + (endpoint: 'mtermvectors', params: MTermVectorsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'ping', params: PingParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'putScript', params: PutScriptParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'putTemplate', params: PutTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'reindex', params: ReindexParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'reindexRethrottle', params: ReindexRethrottleParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'renderSearchTemplate', params: RenderSearchTemplateParams, options?: LegacyCallAPIOptions): ReturnType; // Generic types cannot be properly looked up with ReturnType. Hard code these explicitly. - (endpoint: 'scroll', params: ScrollParams, options?: CallAPIOptions): Promise>; - (endpoint: 'search', params: SearchParams, options?: CallAPIOptions): Promise>; - (endpoint: 'searchShards', params: SearchShardsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'searchTemplate', params: SearchTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'suggest', params: SuggestParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'termvectors', params: TermvectorsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'update', params: UpdateDocumentParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'updateByQuery', params: UpdateDocumentByQueryParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'scroll', params: ScrollParams, options?: LegacyCallAPIOptions): Promise>; + (endpoint: 'search', params: SearchParams, options?: LegacyCallAPIOptions): Promise>; + (endpoint: 'searchShards', params: SearchShardsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'searchTemplate', params: SearchTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'suggest', params: SuggestParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'termvectors', params: TermvectorsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'update', params: UpdateDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'updateByQuery', params: UpdateDocumentByQueryParams, options?: LegacyCallAPIOptions): ReturnType; // cat namespace - (endpoint: 'cat.aliases', params: CatAliasesParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.allocation', params: CatAllocationParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.count', params: CatAllocationParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.fielddata', params: CatFielddataParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.health', params: CatHealthParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.help', params: CatHelpParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.indices', params: CatIndicesParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.master', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.nodeattrs', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.nodes', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.pendingTasks', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.plugins', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.recovery', params: CatRecoveryParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.repositories', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.segments', params: CatSegmentsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.shards', params: CatShardsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.snapshots', params: CatSnapshotsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.tasks', params: CatTasksParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cat.threadPool', params: CatThreadPoolParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'cat.aliases', params: CatAliasesParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.allocation', params: CatAllocationParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.count', params: CatAllocationParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.fielddata', params: CatFielddataParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.health', params: CatHealthParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.help', params: CatHelpParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.indices', params: CatIndicesParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.master', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.nodeattrs', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.nodes', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.pendingTasks', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.plugins', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.recovery', params: CatRecoveryParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.repositories', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.segments', params: CatSegmentsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.shards', params: CatShardsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.snapshots', params: CatSnapshotsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.tasks', params: CatTasksParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cat.threadPool', params: CatThreadPoolParams, options?: LegacyCallAPIOptions): ReturnType; // cluster namespace - (endpoint: 'cluster.allocationExplain', params: ClusterAllocationExplainParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.getSettings', params: ClusterGetSettingsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.health', params: ClusterHealthParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.pendingTasks', params: ClusterPendingTasksParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.putSettings', params: ClusterPutSettingsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.reroute', params: ClusterRerouteParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.state', params: ClusterStateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'cluster.stats', params: ClusterStatsParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'cluster.allocationExplain', params: ClusterAllocationExplainParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.getSettings', params: ClusterGetSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.health', params: ClusterHealthParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.pendingTasks', params: ClusterPendingTasksParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.putSettings', params: ClusterPutSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.reroute', params: ClusterRerouteParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.state', params: ClusterStateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'cluster.stats', params: ClusterStatsParams, options?: LegacyCallAPIOptions): ReturnType; // indices namespace - (endpoint: 'indices.analyze', params: IndicesAnalyzeParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.clearCache', params: IndicesClearCacheParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.close', params: IndicesCloseParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.create', params: IndicesCreateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.delete', params: IndicesDeleteParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.deleteAlias', params: IndicesDeleteAliasParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.deleteTemplate', params: IndicesDeleteTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.exists', params: IndicesExistsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.existsAlias', params: IndicesExistsAliasParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.existsTemplate', params: IndicesExistsTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.existsType', params: IndicesExistsTypeParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.flush', params: IndicesFlushParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.flushSynced', params: IndicesFlushSyncedParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.forcemerge', params: IndicesForcemergeParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.get', params: IndicesGetParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.getAlias', params: IndicesGetAliasParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.getFieldMapping', params: IndicesGetFieldMappingParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.getMapping', params: IndicesGetMappingParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.getSettings', params: IndicesGetSettingsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.getTemplate', params: IndicesGetTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.getUpgrade', params: IndicesGetUpgradeParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.open', params: IndicesOpenParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.putAlias', params: IndicesPutAliasParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.putMapping', params: IndicesPutMappingParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.putSettings', params: IndicesPutSettingsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.putTemplate', params: IndicesPutTemplateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.recovery', params: IndicesRecoveryParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.refresh', params: IndicesRefreshParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.rollover', params: IndicesRolloverParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.segments', params: IndicesSegmentsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.shardStores', params: IndicesShardStoresParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.shrink', params: IndicesShrinkParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.stats', params: IndicesStatsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.updateAliases', params: IndicesUpdateAliasesParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.upgrade', params: IndicesUpgradeParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'indices.validateQuery', params: IndicesValidateQueryParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'indices.analyze', params: IndicesAnalyzeParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.clearCache', params: IndicesClearCacheParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.close', params: IndicesCloseParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.create', params: IndicesCreateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.delete', params: IndicesDeleteParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.deleteAlias', params: IndicesDeleteAliasParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.deleteTemplate', params: IndicesDeleteTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.exists', params: IndicesExistsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.existsAlias', params: IndicesExistsAliasParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.existsTemplate', params: IndicesExistsTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.existsType', params: IndicesExistsTypeParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.flush', params: IndicesFlushParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.flushSynced', params: IndicesFlushSyncedParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.forcemerge', params: IndicesForcemergeParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.get', params: IndicesGetParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.getAlias', params: IndicesGetAliasParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.getFieldMapping', params: IndicesGetFieldMappingParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.getMapping', params: IndicesGetMappingParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.getSettings', params: IndicesGetSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.getTemplate', params: IndicesGetTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.getUpgrade', params: IndicesGetUpgradeParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.open', params: IndicesOpenParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.putAlias', params: IndicesPutAliasParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.putMapping', params: IndicesPutMappingParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.putSettings', params: IndicesPutSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.putTemplate', params: IndicesPutTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.recovery', params: IndicesRecoveryParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.refresh', params: IndicesRefreshParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.rollover', params: IndicesRolloverParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.segments', params: IndicesSegmentsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.shardStores', params: IndicesShardStoresParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.shrink', params: IndicesShrinkParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.stats', params: IndicesStatsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.updateAliases', params: IndicesUpdateAliasesParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.upgrade', params: IndicesUpgradeParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'indices.validateQuery', params: IndicesValidateQueryParams, options?: LegacyCallAPIOptions): ReturnType; // ingest namepsace - (endpoint: 'ingest.deletePipeline', params: IngestDeletePipelineParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'ingest.getPipeline', params: IngestGetPipelineParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'ingest.putPipeline', params: IngestPutPipelineParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'ingest.simulate', params: IngestSimulateParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'ingest.deletePipeline', params: IngestDeletePipelineParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'ingest.getPipeline', params: IngestGetPipelineParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'ingest.putPipeline', params: IngestPutPipelineParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'ingest.simulate', params: IngestSimulateParams, options?: LegacyCallAPIOptions): ReturnType; // nodes namespace - (endpoint: 'nodes.hotThreads', params: NodesHotThreadsParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'nodes.info', params: NodesInfoParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'nodes.stats', params: NodesStatsParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'nodes.hotThreads', params: NodesHotThreadsParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'nodes.info', params: NodesInfoParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'nodes.stats', params: NodesStatsParams, options?: LegacyCallAPIOptions): ReturnType; // snapshot namespace - (endpoint: 'snapshot.create', params: SnapshotCreateParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.createRepository', params: SnapshotCreateRepositoryParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.delete', params: SnapshotDeleteParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.deleteRepository', params: SnapshotDeleteRepositoryParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.get', params: SnapshotGetParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.getRepository', params: SnapshotGetRepositoryParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.restore', params: SnapshotRestoreParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.status', params: SnapshotStatusParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'snapshot.verifyRepository', params: SnapshotVerifyRepositoryParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'snapshot.create', params: SnapshotCreateParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.createRepository', params: SnapshotCreateRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.delete', params: SnapshotDeleteParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.deleteRepository', params: SnapshotDeleteRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.get', params: SnapshotGetParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.getRepository', params: SnapshotGetRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.restore', params: SnapshotRestoreParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.status', params: SnapshotStatusParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'snapshot.verifyRepository', params: SnapshotVerifyRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; // tasks namespace - (endpoint: 'tasks.cancel', params: TasksCancelParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'tasks.get', params: TasksGetParams, options?: CallAPIOptions): ReturnType; - (endpoint: 'tasks.list', params: TasksListParams, options?: CallAPIOptions): ReturnType; + (endpoint: 'tasks.cancel', params: TasksCancelParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'tasks.get', params: TasksGetParams, options?: LegacyCallAPIOptions): ReturnType; + (endpoint: 'tasks.list', params: TasksListParams, options?: LegacyCallAPIOptions): ReturnType; // other APIs accessed via transport.request - (endpoint: 'transport.request', clientParams: AssistantAPIClientParams, options?: CallAPIOptions): Promise< + (endpoint: 'transport.request', clientParams: AssistantAPIClientParams, options?: LegacyCallAPIOptions): Promise< AssistanceAPIResponse >; - (endpoint: 'transport.request', clientParams: DeprecationAPIClientParams, options?: CallAPIOptions): Promise< + (endpoint: 'transport.request', clientParams: DeprecationAPIClientParams, options?: LegacyCallAPIOptions): Promise< DeprecationAPIResponse >; // Catch-all definition - (endpoint: string, clientParams?: Record, options?: CallAPIOptions): Promise; + (endpoint: string, clientParams?: Record, options?: LegacyCallAPIOptions): Promise; /* eslint-enable */ } diff --git a/src/core/server/elasticsearch/cluster_client.test.mocks.ts b/src/core/server/elasticsearch/legacy/cluster_client.test.mocks.ts similarity index 95% rename from src/core/server/elasticsearch/cluster_client.test.mocks.ts rename to src/core/server/elasticsearch/legacy/cluster_client.test.mocks.ts index 6873117aecc35e..08585c2305e9bf 100644 --- a/src/core/server/elasticsearch/cluster_client.test.mocks.ts +++ b/src/core/server/elasticsearch/legacy/cluster_client.test.mocks.ts @@ -29,7 +29,7 @@ jest.mock('elasticsearch', () => { export const MockScopedClusterClient = jest.fn(); jest.mock('./scoped_cluster_client', () => ({ - ScopedClusterClient: MockScopedClusterClient, + LegacyScopedClusterClient: MockScopedClusterClient, })); export const mockParseElasticsearchClientConfig = jest.fn(); diff --git a/src/core/server/elasticsearch/cluster_client.test.ts b/src/core/server/elasticsearch/legacy/cluster_client.test.ts similarity index 91% rename from src/core/server/elasticsearch/cluster_client.test.ts rename to src/core/server/elasticsearch/legacy/cluster_client.test.ts index 820272bdf14b81..9ab4862a1ab4c5 100644 --- a/src/core/server/elasticsearch/cluster_client.test.ts +++ b/src/core/server/elasticsearch/legacy/cluster_client.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ElasticsearchConfig } from './elasticsearch_config'; +import { ElasticsearchConfig } from '../elasticsearch_config'; import { MockClient, @@ -27,10 +27,10 @@ import { import { errors } from 'elasticsearch'; import { get } from 'lodash'; -import { Logger } from '../logging'; -import { loggingSystemMock } from '../logging/logging_system.mock'; -import { httpServerMock } from '../http/http_server.mocks'; -import { ClusterClient } from './cluster_client'; +import { Logger } from '../../logging'; +import { loggingSystemMock } from '../../logging/logging_system.mock'; +import { httpServerMock } from '../../http/http_server.mocks'; +import { LegacyClusterClient } from './cluster_client'; const logger = loggingSystemMock.create(); afterEach(() => jest.clearAllMocks()); @@ -42,7 +42,7 @@ test('#constructor creates client with parsed config', () => { const mockEsConfig = { apiVersion: 'es-version' } as any; const mockLogger = logger.get(); - const clusterClient = new ClusterClient(mockEsConfig, mockLogger); + const clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); expect(clusterClient).toBeDefined(); expect(mockParseElasticsearchClientConfig).toHaveBeenCalledTimes(1); @@ -58,7 +58,7 @@ describe('#callAsInternalUser', () => { ping: jest.Mock; security: { authenticate: jest.Mock }; }; - let clusterClient: ClusterClient; + let clusterClient: LegacyClusterClient; beforeEach(() => { mockEsClientInstance = { @@ -68,7 +68,7 @@ describe('#callAsInternalUser', () => { }; MockClient.mockImplementation(() => mockEsClientInstance); - clusterClient = new ClusterClient({ apiVersion: 'es-version' } as any, logger.get()); + clusterClient = new LegacyClusterClient({ apiVersion: 'es-version' } as any, logger.get()); }); test('fails if cluster client is closed', async () => { @@ -220,7 +220,7 @@ describe('#asScoped', () => { let mockEsClientInstance: { ping: jest.Mock; close: jest.Mock }; let mockScopedEsClientInstance: { ping: jest.Mock; close: jest.Mock }; - let clusterClient: ClusterClient; + let clusterClient: LegacyClusterClient; let mockLogger: Logger; let mockEsConfig: ElasticsearchConfig; @@ -237,7 +237,7 @@ describe('#asScoped', () => { requestHeadersWhitelist: ['one', 'two'], } as any; - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); jest.clearAllMocks(); }); @@ -272,7 +272,7 @@ describe('#asScoped', () => { test('properly configures `ignoreCertAndKey` for various configurations', () => { // Config without SSL. - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); mockParseElasticsearchClientConfig.mockClear(); clusterClient.asScoped(httpServerMock.createRawRequest({ headers: { one: '1' } })); @@ -285,7 +285,7 @@ describe('#asScoped', () => { // Config ssl.alwaysPresentCertificate === false mockEsConfig = { ...mockEsConfig, ssl: { alwaysPresentCertificate: false } } as any; - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); mockParseElasticsearchClientConfig.mockClear(); clusterClient.asScoped(httpServerMock.createRawRequest({ headers: { one: '1' } })); @@ -298,7 +298,7 @@ describe('#asScoped', () => { // Config ssl.alwaysPresentCertificate === true mockEsConfig = { ...mockEsConfig, ssl: { alwaysPresentCertificate: true } } as any; - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); mockParseElasticsearchClientConfig.mockClear(); clusterClient.asScoped(httpServerMock.createRawRequest({ headers: { one: '1' } })); @@ -341,7 +341,7 @@ describe('#asScoped', () => { }); test('does not fail when scope to not defined request', async () => { - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); clusterClient.asScoped(); expect(MockScopedClusterClient).toHaveBeenCalledTimes(1); expect(MockScopedClusterClient).toHaveBeenCalledWith( @@ -352,7 +352,7 @@ describe('#asScoped', () => { }); test('does not fail when scope to a request without headers', async () => { - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); clusterClient.asScoped({} as any); expect(MockScopedClusterClient).toHaveBeenCalledTimes(1); expect(MockScopedClusterClient).toHaveBeenCalledWith( @@ -363,7 +363,10 @@ describe('#asScoped', () => { }); test('calls getAuthHeaders and filters results for a real request', async () => { - clusterClient = new ClusterClient(mockEsConfig, mockLogger, () => ({ one: '1', three: '3' })); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger, () => ({ + one: '1', + three: '3', + })); clusterClient.asScoped(httpServerMock.createRawRequest({ headers: { two: '2' } })); expect(MockScopedClusterClient).toHaveBeenCalledTimes(1); expect(MockScopedClusterClient).toHaveBeenCalledWith( @@ -374,7 +377,7 @@ describe('#asScoped', () => { }); test('getAuthHeaders results rewrite extends a request headers', async () => { - clusterClient = new ClusterClient(mockEsConfig, mockLogger, () => ({ one: 'foo' })); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger, () => ({ one: 'foo' })); clusterClient.asScoped(httpServerMock.createRawRequest({ headers: { one: '1', two: '2' } })); expect(MockScopedClusterClient).toHaveBeenCalledTimes(1); expect(MockScopedClusterClient).toHaveBeenCalledWith( @@ -386,14 +389,14 @@ describe('#asScoped', () => { test("doesn't call getAuthHeaders for a fake request", async () => { const getAuthHeaders = jest.fn(); - clusterClient = new ClusterClient(mockEsConfig, mockLogger, getAuthHeaders); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger, getAuthHeaders); clusterClient.asScoped({ headers: { one: '1', two: '2', three: '3' } }); expect(getAuthHeaders).not.toHaveBeenCalled(); }); test('filters a fake request headers', async () => { - clusterClient = new ClusterClient(mockEsConfig, mockLogger); + clusterClient = new LegacyClusterClient(mockEsConfig, mockLogger); clusterClient.asScoped({ headers: { one: '1', two: '2', three: '3' } }); expect(MockScopedClusterClient).toHaveBeenCalledTimes(1); @@ -409,7 +412,7 @@ describe('#close', () => { let mockEsClientInstance: { close: jest.Mock }; let mockScopedEsClientInstance: { close: jest.Mock }; - let clusterClient: ClusterClient; + let clusterClient: LegacyClusterClient; beforeEach(() => { mockEsClientInstance = { close: jest.fn() }; @@ -418,7 +421,7 @@ describe('#close', () => { () => mockScopedEsClientInstance ); - clusterClient = new ClusterClient( + clusterClient = new LegacyClusterClient( { apiVersion: 'es-version', requestHeadersWhitelist: [] } as any, logger.get() ); diff --git a/src/core/server/elasticsearch/cluster_client.ts b/src/core/server/elasticsearch/legacy/cluster_client.ts similarity index 77% rename from src/core/server/elasticsearch/cluster_client.ts rename to src/core/server/elasticsearch/legacy/cluster_client.ts index 2352677b8d3e0a..8e2d20a8972fc9 100644 --- a/src/core/server/elasticsearch/cluster_client.ts +++ b/src/core/server/elasticsearch/legacy/cluster_client.ts @@ -19,16 +19,17 @@ import { Client } from 'elasticsearch'; import { get } from 'lodash'; -import { ElasticsearchErrorHelpers } from './errors'; -import { GetAuthHeaders, isRealRequest, LegacyRequest } from '../http'; -import { filterHeaders, Headers, KibanaRequest, ensureRawRequest } from '../http/router'; -import { Logger } from '../logging'; +import { LegacyElasticsearchErrorHelpers } from './errors'; +import { GetAuthHeaders, isRealRequest } from '../../http'; +import { filterHeaders, ensureRawRequest } from '../../http/router'; +import { Logger } from '../../logging'; +import { ScopeableRequest } from '../types'; import { - ElasticsearchClientConfig, + LegacyElasticsearchClientConfig, parseElasticsearchClientConfig, } from './elasticsearch_client_config'; -import { ScopedClusterClient, IScopedClusterClient } from './scoped_cluster_client'; -import { CallAPIOptions, APICaller } from './api_types'; +import { LegacyScopedClusterClient, ILegacyScopedClusterClient } from './scoped_cluster_client'; +import { LegacyCallAPIOptions, LegacyAPICaller } from './api_types'; /** * Support Legacy platform request for the period of migration. @@ -50,7 +51,7 @@ const callAPI = async ( client: Client, endpoint: string, clientParams: Record = {}, - options: CallAPIOptions = { wrap401Errors: true } + options: LegacyCallAPIOptions = { wrap401Errors: true } ) => { const clientPath = endpoint.split('.'); const api: any = get(client, clientPath); @@ -75,55 +76,40 @@ const callAPI = async ( throw err; } - throw ElasticsearchErrorHelpers.decorateNotAuthorizedError(err); + throw LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError(err); } }; -/** - * Fake request object created manually by Kibana plugins. - * @public - */ -export interface FakeRequest { - /** Headers used for authentication against Elasticsearch */ - headers: Headers; -} - /** * Represents an Elasticsearch cluster API client created by the platform. * It allows to call API on behalf of the internal Kibana user and * the actual user that is derived from the request headers (via `asScoped(...)`). * - * See {@link ClusterClient}. + * See {@link LegacyClusterClient}. * * @public */ -export type IClusterClient = Pick; +export type ILegacyClusterClient = Pick; /** * Represents an Elasticsearch cluster API client created by a plugin. * It allows to call API on behalf of the internal Kibana user and * the actual user that is derived from the request headers (via `asScoped(...)`). * - * See {@link ClusterClient}. - * - * @public - */ -export type ICustomClusterClient = Pick; - -/** - A user credentials container. - * It accommodates the necessary auth credentials to impersonate the current user. + * See {@link LegacyClusterClient}. * * @public - * See {@link KibanaRequest}. */ -export type ScopeableRequest = KibanaRequest | LegacyRequest | FakeRequest; +export type ILegacyCustomClusterClient = Pick< + LegacyClusterClient, + 'callAsInternalUser' | 'close' | 'asScoped' +>; /** * {@inheritDoc IClusterClient} * @public */ -export class ClusterClient implements IClusterClient { +export class LegacyClusterClient implements ILegacyClusterClient { /** * Raw Elasticsearch JS client that acts on behalf of the Kibana internal user. */ @@ -141,7 +127,7 @@ export class ClusterClient implements IClusterClient { private isClosed = false; constructor( - private readonly config: ElasticsearchClientConfig, + private readonly config: LegacyElasticsearchClientConfig, private readonly log: Logger, private readonly getAuthHeaders: GetAuthHeaders = noop ) { @@ -151,20 +137,24 @@ export class ClusterClient implements IClusterClient { /** * Calls specified endpoint with provided clientParams on behalf of the * Kibana internal user. - * See {@link APICaller}. + * See {@link LegacyAPICaller}. * * @param endpoint - String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. * @param clientParams - A dictionary of parameters that will be passed directly to the Elasticsearch JS client. * @param options - Options that affect the way we call the API and process the result. */ - public callAsInternalUser: APICaller = async ( + public callAsInternalUser: LegacyAPICaller = async ( endpoint: string, clientParams: Record = {}, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) => { this.assertIsNotClosed(); - return await (callAPI.bind(null, this.client) as APICaller)(endpoint, clientParams, options); + return await (callAPI.bind(null, this.client) as LegacyAPICaller)( + endpoint, + clientParams, + options + ); }; /** @@ -185,7 +175,7 @@ export class ClusterClient implements IClusterClient { } /** - * Creates an instance of {@link IScopedClusterClient} based on the configuration the + * Creates an instance of {@link ILegacyScopedClusterClient} based on the configuration the * current cluster client that exposes additional `callAsCurrentUser` method * scoped to the provided req. Consumers shouldn't worry about closing * scoped client instances, these will be automatically closed as soon as the @@ -194,7 +184,7 @@ export class ClusterClient implements IClusterClient { * @param request - Request the `IScopedClusterClient` instance will be scoped to. * Supports request optionality, Legacy.Request & FakeRequest for BWC with LegacyPlatform */ - public asScoped(request?: ScopeableRequest): IScopedClusterClient { + public asScoped(request?: ScopeableRequest): ILegacyScopedClusterClient { // It'd have been quite expensive to create and configure client for every incoming // request since it involves parsing of the config, reading of the SSL certificate and // key files etc. Moreover scoped client needs two Elasticsearch JS clients at the same @@ -210,7 +200,7 @@ export class ClusterClient implements IClusterClient { ); } - return new ScopedClusterClient( + return new LegacyScopedClusterClient( this.callAsInternalUser, this.callAsCurrentUser, filterHeaders(this.getHeaders(request), this.config.requestHeadersWhitelist) @@ -220,20 +210,20 @@ export class ClusterClient implements IClusterClient { /** * Calls specified endpoint with provided clientParams on behalf of the * user initiated request to the Kibana server (via HTTP request headers). - * See {@link APICaller}. + * See {@link LegacyAPICaller}. * * @param endpoint - String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. * @param clientParams - A dictionary of parameters that will be passed directly to the Elasticsearch JS client. * @param options - Options that affect the way we call the API and process the result. */ - private callAsCurrentUser: APICaller = async ( + private callAsCurrentUser: LegacyAPICaller = async ( endpoint: string, clientParams: Record = {}, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) => { this.assertIsNotClosed(); - return await (callAPI.bind(null, this.scopedClient!) as APICaller)( + return await (callAPI.bind(null, this.scopedClient!) as LegacyAPICaller)( endpoint, clientParams, options @@ -246,9 +236,7 @@ export class ClusterClient implements IClusterClient { } } - private getHeaders( - request?: KibanaRequest | LegacyRequest | FakeRequest - ): Record { + private getHeaders(request?: ScopeableRequest): Record { if (!isRealRequest(request)) { return request && request.headers ? request.headers : {}; } diff --git a/src/core/server/elasticsearch/elasticsearch_client_config.test.ts b/src/core/server/elasticsearch/legacy/elasticsearch_client_config.test.ts similarity index 98% rename from src/core/server/elasticsearch/elasticsearch_client_config.test.ts rename to src/core/server/elasticsearch/legacy/elasticsearch_client_config.test.ts index 77d1e41c9ad833..d6b65da7726d26 100644 --- a/src/core/server/elasticsearch/elasticsearch_client_config.test.ts +++ b/src/core/server/elasticsearch/legacy/elasticsearch_client_config.test.ts @@ -18,9 +18,9 @@ */ import { duration } from 'moment'; -import { loggingSystemMock } from '../logging/logging_system.mock'; +import { loggingSystemMock } from '../../logging/logging_system.mock'; import { - ElasticsearchClientConfig, + LegacyElasticsearchClientConfig, parseElasticsearchClientConfig, } from './elasticsearch_client_config'; const logger = loggingSystemMock.create(); @@ -64,7 +64,7 @@ Object { }); test('parses fully specified config', () => { - const elasticsearchConfig: ElasticsearchClientConfig = { + const elasticsearchConfig: LegacyElasticsearchClientConfig = { apiVersion: 'v7.0.0', customHeaders: { xsrf: 'something' }, logQueries: true, diff --git a/src/core/server/elasticsearch/elasticsearch_client_config.ts b/src/core/server/elasticsearch/legacy/elasticsearch_client_config.ts similarity index 93% rename from src/core/server/elasticsearch/elasticsearch_client_config.ts rename to src/core/server/elasticsearch/legacy/elasticsearch_client_config.ts index 287d835c40351b..260a60ac74f118 100644 --- a/src/core/server/elasticsearch/elasticsearch_client_config.ts +++ b/src/core/server/elasticsearch/legacy/elasticsearch_client_config.ts @@ -22,9 +22,9 @@ import { cloneDeep } from 'lodash'; import { Duration } from 'moment'; import { checkServerIdentity } from 'tls'; import url from 'url'; -import { pick } from '../../utils'; -import { Logger } from '../logging'; -import { ElasticsearchConfig } from './elasticsearch_config'; +import { pick } from '../../../utils'; +import { Logger } from '../../logging'; +import { ElasticsearchConfig } from '../elasticsearch_config'; /** * @privateRemarks Config that consumers can pass to the Elasticsearch JS client is complex and includes @@ -33,7 +33,7 @@ import { ElasticsearchConfig } from './elasticsearch_config'; * * @public */ -export type ElasticsearchClientConfig = Pick & +export type LegacyElasticsearchClientConfig = Pick & Pick< ElasticsearchConfig, | 'apiVersion' @@ -53,7 +53,7 @@ export type ElasticsearchClientConfig = Pick { describe('NotAuthorized error', () => { describe('decorateNotAuthorizedError', () => { it('returns original object', () => { const error = new Error(); - expect(ElasticsearchErrorHelpers.decorateNotAuthorizedError(error)).toBe(error); + expect(LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError(error)).toBe(error); }); it('makes the error identifiable as a NotAuthorized error', () => { const error = new Error(); - expect(ElasticsearchErrorHelpers.isNotAuthorizedError(error)).toBe(false); - ElasticsearchErrorHelpers.decorateNotAuthorizedError(error); - expect(ElasticsearchErrorHelpers.isNotAuthorizedError(error)).toBe(true); + expect(LegacyElasticsearchErrorHelpers.isNotAuthorizedError(error)).toBe(false); + LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError(error); + expect(LegacyElasticsearchErrorHelpers.isNotAuthorizedError(error)).toBe(true); }); it('adds boom properties', () => { - const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error()); + const error = LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error()); expect(typeof error.output).toBe('object'); expect(error.output.statusCode).toBe(401); }); it('preserves boom properties of input', () => { const error = Boom.notFound(); - ElasticsearchErrorHelpers.decorateNotAuthorizedError(error); + LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError(error); expect(error.output.statusCode).toBe(404); }); describe('error.output', () => { it('defaults to message of error', () => { - const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error('foobar')); + const error = LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError( + new Error('foobar') + ); expect(error.output.payload).toHaveProperty('message', 'foobar'); }); it('prefixes message with passed reason', () => { - const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError( + const error = LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError( new Error('foobar'), 'biz' ); expect(error.output.payload).toHaveProperty('message', 'biz: foobar'); }); it('sets statusCode to 401', () => { - const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error('foo')); + const error = LegacyElasticsearchErrorHelpers.decorateNotAuthorizedError( + new Error('foo') + ); expect(error.output).toHaveProperty('statusCode', 401); }); }); diff --git a/src/core/server/elasticsearch/errors.ts b/src/core/server/elasticsearch/legacy/errors.ts similarity index 88% rename from src/core/server/elasticsearch/errors.ts rename to src/core/server/elasticsearch/legacy/errors.ts index 6852b8632ebf12..f81903d76547a3 100644 --- a/src/core/server/elasticsearch/errors.ts +++ b/src/core/server/elasticsearch/legacy/errors.ts @@ -27,11 +27,11 @@ enum ErrorCode { } /** @public */ -export interface ElasticsearchError extends Boom { +export interface LegacyElasticsearchError extends Boom { [code]?: string; } -function isElasticsearchError(error: any): error is ElasticsearchError { +function isElasticsearchError(error: any): error is LegacyElasticsearchError { return Boolean(error && error[code]); } @@ -40,7 +40,7 @@ function decorate( errorCode: ErrorCode, statusCode: number, message?: string -): ElasticsearchError { +): LegacyElasticsearchError { if (isElasticsearchError(error)) { return error; } @@ -50,7 +50,7 @@ function decorate( message, // keep status and messages if Boom error object already has them override: false, - }) as ElasticsearchError; + }) as LegacyElasticsearchError; boom[code] = errorCode; @@ -74,8 +74,8 @@ function decorate( * } * ``` */ -export class ElasticsearchErrorHelpers { - public static isNotAuthorizedError(error: any): error is ElasticsearchError { +export class LegacyElasticsearchErrorHelpers { + public static isNotAuthorizedError(error: any): error is LegacyElasticsearchError { return isElasticsearchError(error) && error[code] === ErrorCode.NOT_AUTHORIZED; } diff --git a/src/core/server/elasticsearch/legacy/index.ts b/src/core/server/elasticsearch/legacy/index.ts new file mode 100644 index 00000000000000..165980b9f45223 --- /dev/null +++ b/src/core/server/elasticsearch/legacy/index.ts @@ -0,0 +1,28 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export { + LegacyClusterClient, + ILegacyClusterClient, + ILegacyCustomClusterClient, +} from './cluster_client'; +export { ILegacyScopedClusterClient, LegacyScopedClusterClient } from './scoped_cluster_client'; +export { LegacyElasticsearchClientConfig } from './elasticsearch_client_config'; +export { retryCallCluster, migrationsRetryCallCluster } from './retry_call_cluster'; +export { LegacyElasticsearchError, LegacyElasticsearchErrorHelpers } from './errors'; +export * from './api_types'; diff --git a/src/core/server/elasticsearch/retry_call_cluster.test.ts b/src/core/server/elasticsearch/legacy/retry_call_cluster.test.ts similarity index 98% rename from src/core/server/elasticsearch/retry_call_cluster.test.ts rename to src/core/server/elasticsearch/legacy/retry_call_cluster.test.ts index 18ffa95048c4d9..62789a4fe952d7 100644 --- a/src/core/server/elasticsearch/retry_call_cluster.test.ts +++ b/src/core/server/elasticsearch/legacy/retry_call_cluster.test.ts @@ -19,7 +19,7 @@ import * as legacyElasticsearch from 'elasticsearch'; import { retryCallCluster, migrationsRetryCallCluster } from './retry_call_cluster'; -import { loggingSystemMock } from '../logging/logging_system.mock'; +import { loggingSystemMock } from '../../logging/logging_system.mock'; describe('retryCallCluster', () => { it('retries ES API calls that rejects with NoConnections', () => { diff --git a/src/core/server/elasticsearch/retry_call_cluster.ts b/src/core/server/elasticsearch/legacy/retry_call_cluster.ts similarity index 87% rename from src/core/server/elasticsearch/retry_call_cluster.ts rename to src/core/server/elasticsearch/legacy/retry_call_cluster.ts index aa3e39d948593a..475a76d4060171 100644 --- a/src/core/server/elasticsearch/retry_call_cluster.ts +++ b/src/core/server/elasticsearch/legacy/retry_call_cluster.ts @@ -21,9 +21,9 @@ import { retryWhen, concatMap } from 'rxjs/operators'; import { defer, throwError, iif, timer } from 'rxjs'; import * as legacyElasticsearch from 'elasticsearch'; -import { CallAPIOptions } from '.'; -import { APICaller } from './api_types'; -import { Logger } from '../logging'; +import { LegacyCallAPIOptions } from '.'; +import { LegacyAPICaller } from './api_types'; +import { Logger } from '../../logging'; const esErrors = legacyElasticsearch.errors; @@ -39,12 +39,16 @@ const esErrors = legacyElasticsearch.errors; * @param delay */ export function migrationsRetryCallCluster( - apiCaller: APICaller, + apiCaller: LegacyAPICaller, log: Logger, delay: number = 2500 ) { const previousErrors: string[] = []; - return (endpoint: string, clientParams: Record = {}, options?: CallAPIOptions) => { + return ( + endpoint: string, + clientParams: Record = {}, + options?: LegacyCallAPIOptions + ) => { return defer(() => apiCaller(endpoint, clientParams, options)) .pipe( retryWhen((error$) => @@ -63,7 +67,7 @@ export function migrationsRetryCallCluster( error instanceof esErrors.RequestTimeout || error instanceof esErrors.AuthenticationException || error instanceof esErrors.AuthorizationException || - // @ts-ignore + // @ts-expect-error error instanceof esErrors.Gone || error?.body?.error?.type === 'snapshot_in_progress_exception' ); @@ -86,8 +90,12 @@ export function migrationsRetryCallCluster( * * @param apiCaller */ -export function retryCallCluster(apiCaller: APICaller) { - return (endpoint: string, clientParams: Record = {}, options?: CallAPIOptions) => { +export function retryCallCluster(apiCaller: LegacyAPICaller) { + return ( + endpoint: string, + clientParams: Record = {}, + options?: LegacyCallAPIOptions + ) => { return defer(() => apiCaller(endpoint, clientParams, options)) .pipe( retryWhen((errors) => diff --git a/src/core/server/elasticsearch/scoped_cluster_client.test.ts b/src/core/server/elasticsearch/legacy/scoped_cluster_client.test.ts similarity index 95% rename from src/core/server/elasticsearch/scoped_cluster_client.test.ts rename to src/core/server/elasticsearch/legacy/scoped_cluster_client.test.ts index 04c13f85a1ef7a..2eb8cefb564ae6 100644 --- a/src/core/server/elasticsearch/scoped_cluster_client.test.ts +++ b/src/core/server/elasticsearch/legacy/scoped_cluster_client.test.ts @@ -17,15 +17,15 @@ * under the License. */ -import { ScopedClusterClient } from './scoped_cluster_client'; +import { LegacyScopedClusterClient } from './scoped_cluster_client'; let internalAPICaller: jest.Mock; let scopedAPICaller: jest.Mock; -let clusterClient: ScopedClusterClient; +let clusterClient: LegacyScopedClusterClient; beforeEach(() => { internalAPICaller = jest.fn(); scopedAPICaller = jest.fn(); - clusterClient = new ScopedClusterClient(internalAPICaller, scopedAPICaller, { one: '1' }); + clusterClient = new LegacyScopedClusterClient(internalAPICaller, scopedAPICaller, { one: '1' }); }); afterEach(() => jest.clearAllMocks()); @@ -184,7 +184,10 @@ describe('#callAsCurrentUser', () => { const mockResponse = { data: 'response' }; scopedAPICaller.mockResolvedValue(mockResponse); - const clusterClientWithoutHeaders = new ScopedClusterClient(internalAPICaller, scopedAPICaller); + const clusterClientWithoutHeaders = new LegacyScopedClusterClient( + internalAPICaller, + scopedAPICaller + ); await expect(clusterClientWithoutHeaders.callAsCurrentUser('ping')).resolves.toBe(mockResponse); expect(scopedAPICaller).toHaveBeenCalledTimes(1); diff --git a/src/core/server/elasticsearch/scoped_cluster_client.ts b/src/core/server/elasticsearch/legacy/scoped_cluster_client.ts similarity index 85% rename from src/core/server/elasticsearch/scoped_cluster_client.ts rename to src/core/server/elasticsearch/legacy/scoped_cluster_client.ts index 4b64bfba151907..e62409ff00c7ed 100644 --- a/src/core/server/elasticsearch/scoped_cluster_client.ts +++ b/src/core/server/elasticsearch/legacy/scoped_cluster_client.ts @@ -18,11 +18,8 @@ */ import { intersection, isObject } from 'lodash'; -import { Headers } from '../http/router'; -import { APICaller, CallAPIOptions } from './api_types'; - -/** @public */ -export { Headers }; +import { Headers } from '../../http/router'; +import { LegacyAPICaller, LegacyCallAPIOptions } from './api_types'; /** * Serves the same purpose as "normal" `ClusterClient` but exposes additional @@ -30,12 +27,12 @@ export { Headers }; * user (as `callAsInternalUser` does) to request Elasticsearch API, but rather * passes HTTP headers extracted from the current user request to the API. * - * See {@link ScopedClusterClient}. + * See {@link LegacyScopedClusterClient}. * * @public */ -export type IScopedClusterClient = Pick< - ScopedClusterClient, +export type ILegacyScopedClusterClient = Pick< + LegacyScopedClusterClient, 'callAsCurrentUser' | 'callAsInternalUser' >; @@ -43,10 +40,10 @@ export type IScopedClusterClient = Pick< * {@inheritDoc IScopedClusterClient} * @public */ -export class ScopedClusterClient implements IScopedClusterClient { +export class LegacyScopedClusterClient implements ILegacyScopedClusterClient { constructor( - private readonly internalAPICaller: APICaller, - private readonly scopedAPICaller: APICaller, + private readonly internalAPICaller: LegacyAPICaller, + private readonly scopedAPICaller: LegacyAPICaller, private readonly headers?: Headers ) { this.callAsCurrentUser = this.callAsCurrentUser.bind(this); @@ -56,7 +53,7 @@ export class ScopedClusterClient implements IScopedClusterClient { /** * Calls specified `endpoint` with provided `clientParams` on behalf of the * Kibana internal user. - * See {@link APICaller}. + * See {@link LegacyAPICaller}. * * @param endpoint - String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. * @param clientParams - A dictionary of parameters that will be passed directly to the Elasticsearch JS client. @@ -65,7 +62,7 @@ export class ScopedClusterClient implements IScopedClusterClient { public callAsInternalUser( endpoint: string, clientParams: Record = {}, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) { return this.internalAPICaller(endpoint, clientParams, options); } @@ -73,7 +70,7 @@ export class ScopedClusterClient implements IScopedClusterClient { /** * Calls specified `endpoint` with provided `clientParams` on behalf of the * user initiated request to the Kibana server (via HTTP request headers). - * See {@link APICaller}. + * See {@link LegacyAPICaller}. * * @param endpoint - String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. * @param clientParams - A dictionary of parameters that will be passed directly to the Elasticsearch JS client. @@ -82,7 +79,7 @@ export class ScopedClusterClient implements IScopedClusterClient { public callAsCurrentUser( endpoint: string, clientParams: Record = {}, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) { const defaultHeaders = this.headers; if (defaultHeaders !== undefined) { diff --git a/src/core/server/elasticsearch/types.ts b/src/core/server/elasticsearch/types.ts index 6fef08fc298ffa..2b4ba4b0a0a550 100644 --- a/src/core/server/elasticsearch/types.ts +++ b/src/core/server/elasticsearch/types.ts @@ -18,9 +18,14 @@ */ import { Observable } from 'rxjs'; +import { Headers } from '../http/router'; +import { LegacyRequest, KibanaRequest } from '../http'; import { ElasticsearchConfig } from './elasticsearch_config'; -import { ElasticsearchClientConfig } from './elasticsearch_client_config'; -import { IClusterClient, ICustomClusterClient } from './cluster_client'; +import { + LegacyElasticsearchClientConfig, + ILegacyClusterClient, + ILegacyCustomClusterClient, +} from './legacy'; import { NodesVersionCompatibility } from './version_check/ensure_es_version'; import { ServiceStatus } from '../status'; @@ -38,7 +43,7 @@ export interface ElasticsearchServiceSetup { * @deprecated * Use {@link ElasticsearchServiceStart.legacy | ElasticsearchServiceStart.legacy.createClient} instead. * - * Create application specific Elasticsearch cluster API client with customized config. See {@link IClusterClient}. + * Create application specific Elasticsearch cluster API client with customized config. See {@link ILegacyClusterClient}. * * @param type Unique identifier of the client * @param clientConfig A config consists of Elasticsearch JS client options and @@ -56,22 +61,22 @@ export interface ElasticsearchServiceSetup { */ readonly createClient: ( type: string, - clientConfig?: Partial - ) => ICustomClusterClient; + clientConfig?: Partial + ) => ILegacyCustomClusterClient; /** * @deprecated * Use {@link ElasticsearchServiceStart.legacy | ElasticsearchServiceStart.legacy.client} instead. * * All Elasticsearch config value changes are processed under the hood. - * See {@link IClusterClient}. + * See {@link ILegacyClusterClient}. * * @example * ```js * const client = core.elasticsearch.legacy.client; * ``` */ - readonly client: IClusterClient; + readonly client: ILegacyClusterClient; }; } @@ -86,7 +91,7 @@ export interface ElasticsearchServiceStart { * */ legacy: { /** - * Create application specific Elasticsearch cluster API client with customized config. See {@link IClusterClient}. + * Create application specific Elasticsearch cluster API client with customized config. See {@link ILegacyClusterClient}. * * @param type Unique identifier of the client * @param clientConfig A config consists of Elasticsearch JS client options and @@ -104,19 +109,19 @@ export interface ElasticsearchServiceStart { */ readonly createClient: ( type: string, - clientConfig?: Partial - ) => ICustomClusterClient; + clientConfig?: Partial + ) => ILegacyCustomClusterClient; /** * A pre-configured Elasticsearch client. All Elasticsearch config value changes are processed under the hood. - * See {@link IClusterClient}. + * See {@link ILegacyClusterClient}. * * @example * ```js * const client = core.elasticsearch.client; * ``` */ - readonly client: IClusterClient; + readonly client: ILegacyClusterClient; }; } @@ -135,3 +140,21 @@ export interface ElasticsearchStatusMeta { warningNodes: NodesVersionCompatibility['warningNodes']; incompatibleNodes: NodesVersionCompatibility['incompatibleNodes']; } + +/** + * Fake request object created manually by Kibana plugins. + * @public + */ +export interface FakeRequest { + /** Headers used for authentication against Elasticsearch */ + headers: Headers; +} + +/** + A user credentials container. + * It accommodates the necessary auth credentials to impersonate the current user. + * + * @public + * See {@link KibanaRequest}. + */ +export type ScopeableRequest = KibanaRequest | LegacyRequest | FakeRequest; diff --git a/src/core/server/elasticsearch/version_check/ensure_es_version.ts b/src/core/server/elasticsearch/version_check/ensure_es_version.ts index 776298e5869a0d..3f562dac22a028 100644 --- a/src/core/server/elasticsearch/version_check/ensure_es_version.ts +++ b/src/core/server/elasticsearch/version_check/ensure_es_version.ts @@ -29,10 +29,10 @@ import { esVersionEqualsKibana, } from './es_kibana_version_compatability'; import { Logger } from '../../logging'; -import { APICaller } from '..'; +import { LegacyAPICaller } from '..'; export interface PollEsNodesVersionOptions { - callWithInternalUser: APICaller; + callWithInternalUser: LegacyAPICaller; log: Logger; kibanaVersion: string; ignoreVersionMismatch: boolean; diff --git a/src/core/server/http/cookie_session_storage.ts b/src/core/server/http/cookie_session_storage.ts index 13f498233f695b..5ca70045f81db6 100644 --- a/src/core/server/http/cookie_session_storage.ts +++ b/src/core/server/http/cookie_session_storage.ts @@ -19,7 +19,7 @@ import { Request, Server } from 'hapi'; import hapiAuthCookie from 'hapi-auth-cookie'; -// @ts-ignore no TS definitions +// @ts-expect-error no TS definitions import Statehood from 'statehood'; import { KibanaRequest, ensureRawRequest } from './router'; diff --git a/src/core/server/http/index.ts b/src/core/server/http/index.ts index ca9dfde2e71dce..65d633260a7911 100644 --- a/src/core/server/http/index.ts +++ b/src/core/server/http/index.ts @@ -25,6 +25,7 @@ export { CustomHttpResponseOptions, IKibanaSocket, isRealRequest, + Headers, HttpResponseOptions, HttpResponsePayload, ErrorHttpResponseOptions, diff --git a/src/core/server/http/integration_tests/core_service.test.mocks.ts b/src/core/server/http/integration_tests/core_service.test.mocks.ts index 8e782970e2a8e4..6f9b4b96eae9d6 100644 --- a/src/core/server/http/integration_tests/core_service.test.mocks.ts +++ b/src/core/server/http/integration_tests/core_service.test.mocks.ts @@ -19,8 +19,8 @@ import { elasticsearchServiceMock } from '../../elasticsearch/elasticsearch_service.mock'; export const clusterClientMock = jest.fn(); -jest.doMock('../../elasticsearch/scoped_cluster_client', () => ({ - ScopedClusterClient: clusterClientMock.mockImplementation(function () { +jest.doMock('../../elasticsearch/legacy/scoped_cluster_client', () => ({ + LegacyScopedClusterClient: clusterClientMock.mockImplementation(function () { return elasticsearchServiceMock.createScopedClusterClient(); }), })); diff --git a/src/core/server/http/router/request.ts b/src/core/server/http/router/request.ts index f266677c1a1727..fefd75ad9710e9 100644 --- a/src/core/server/http/router/request.ts +++ b/src/core/server/http/router/request.ts @@ -21,8 +21,9 @@ import { Url } from 'url'; import { Request, ApplicationState } from 'hapi'; import { Observable, fromEvent, merge } from 'rxjs'; import { shareReplay, first, takeUntil } from 'rxjs/operators'; +import { RecursiveReadonly } from '@kbn/utility-types'; -import { deepFreeze, RecursiveReadonly } from '../../../utils'; +import { deepFreeze } from '../../../utils'; import { Headers } from './headers'; import { RouteMethod, RouteConfigOptions, validBodyOutput, isSafeMethod } from './route'; import { KibanaSocket, IKibanaSocket } from './socket'; @@ -156,7 +157,7 @@ export class KibanaRequest< public readonly params: Params, public readonly query: Query, public readonly body: Body, - // @ts-ignore we will use this flag as soon as http request proxy is supported in the core + // @ts-expect-error we will use this flag as soon as http request proxy is supported in the core // until that time we have to expose all the headers private readonly withoutSecretHeaders: boolean ) { diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 7520111bf33ac5..35aabab4a0b26b 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -41,7 +41,7 @@ import { ElasticsearchServiceSetup, - IScopedClusterClient, + ILegacyScopedClusterClient, configSchema as elasticsearchConfigSchema, ElasticsearchServiceStart, } from './elasticsearch'; @@ -91,25 +91,24 @@ export { export { CoreId } from './core_context'; export { CspConfig, ICspConfig } from './csp'; export { - ClusterClient, - IClusterClient, - ICustomClusterClient, - Headers, - ScopedClusterClient, - IScopedClusterClient, + LegacyClusterClient, + ILegacyClusterClient, + ILegacyCustomClusterClient, + LegacyScopedClusterClient, + ILegacyScopedClusterClient, ElasticsearchConfig, - ElasticsearchClientConfig, - ElasticsearchError, - ElasticsearchErrorHelpers, + LegacyElasticsearchClientConfig, + LegacyElasticsearchError, + LegacyElasticsearchErrorHelpers, ElasticsearchServiceSetup, ElasticsearchServiceStart, ElasticsearchStatusMeta, NodesVersionCompatibility, - APICaller, + LegacyAPICaller, FakeRequest, ScopeableRequest, } from './elasticsearch'; -export * from './elasticsearch/api_types'; +export * from './elasticsearch/legacy/api_types'; export { AuthenticationHandler, AuthHeaders, @@ -127,6 +126,7 @@ export { CustomHttpResponseOptions, GetAuthHeaders, GetAuthState, + Headers, HttpAuth, HttpResponseOptions, HttpResponsePayload, @@ -307,7 +307,6 @@ export { } from './metrics'; export { - RecursiveReadonly, DEFAULT_APP_CATEGORIES, getFlattenedObject, URLMeaningfulParts, @@ -356,7 +355,7 @@ export { * which uses the credentials of the incoming request * - {@link ISavedObjectTypeRegistry | savedObjects.typeRegistry} - Type registry containing * all the registered types. - * - {@link ScopedClusterClient | elasticsearch.legacy.client} - Elasticsearch + * - {@link LegacyScopedClusterClient | elasticsearch.legacy.client} - Elasticsearch * data client which uses the credentials of the incoming request * - {@link IUiSettingsClient | uiSettings.client} - uiSettings client * which uses the credentials of the incoming request @@ -371,7 +370,7 @@ export interface RequestHandlerContext { }; elasticsearch: { legacy: { - client: IScopedClusterClient; + client: ILegacyScopedClusterClient; }; }; uiSettings: { diff --git a/src/core/server/legacy/config/get_unused_config_keys.ts b/src/core/server/legacy/config/get_unused_config_keys.ts index 6cd193d896109d..8e53178142180e 100644 --- a/src/core/server/legacy/config/get_unused_config_keys.ts +++ b/src/core/server/legacy/config/get_unused_config_keys.ts @@ -18,7 +18,7 @@ */ import { difference, get, set } from 'lodash'; -// @ts-ignore +// @ts-expect-error import { getTransform } from '../../../../legacy/deprecation/index'; import { unset } from '../../../../legacy/utils'; import { getFlattenedObject } from '../../../utils'; diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index ccadae757fe546..ffe3b2375bc901 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -29,7 +29,6 @@ import { import { BehaviorSubject, throwError } from 'rxjs'; -// @ts-ignore: implicit any for JS file import { ClusterManager as MockClusterManager } from '../../../cli/cluster/cluster_manager'; import KbnServer from '../../../legacy/server/kbn_server'; import { Config, Env, ObjectToConfigAdapter } from '../config'; diff --git a/src/core/server/legacy/logging/legacy_logging_server.ts b/src/core/server/legacy/logging/legacy_logging_server.ts index 85a8686b4eded6..4a7fea87cf69f8 100644 --- a/src/core/server/legacy/logging/legacy_logging_server.ts +++ b/src/core/server/legacy/logging/legacy_logging_server.ts @@ -19,9 +19,9 @@ import { ServerExtType } from 'hapi'; import Podium from 'podium'; -// @ts-ignore: implicit any for JS file +// @ts-expect-error: implicit any for JS file import { Config } from '../../../../legacy/server/config'; -// @ts-ignore: implicit any for JS file +// @ts-expect-error: implicit any for JS file import { setupLogging } from '../../../../legacy/server/logging'; import { LogLevel } from '../../logging/log_level'; import { LogRecord } from '../../logging/log_record'; diff --git a/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts b/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts index 5039b3a55cc58f..f3ec2ed8335c5a 100644 --- a/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts +++ b/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts @@ -23,7 +23,7 @@ import { toArray, tap, distinct, map } from 'rxjs/operators'; import { findPluginSpecs, defaultConfig, - // @ts-ignore + // @ts-expect-error } from '../../../../legacy/plugin_discovery/find_plugin_specs.js'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { collectUiExports as collectLegacyUiExports } from '../../../../legacy/ui/ui_exports/collect_ui_exports'; diff --git a/src/core/server/logging/logging_system.test.ts b/src/core/server/logging/logging_system.test.ts index f73e40fe320dc3..ac52973081106e 100644 --- a/src/core/server/logging/logging_system.test.ts +++ b/src/core/server/logging/logging_system.test.ts @@ -230,6 +230,49 @@ test('setContextConfig() updates config with relative contexts', () => { ); }); +test('setContextConfig() updates config for a root context', () => { + const testsLogger = system.get('tests'); + const testsChildLogger = system.get('tests', 'child'); + const testsGrandchildLogger = system.get('tests', 'child', 'grandchild'); + + system.upgrade( + config.schema.validate({ + appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + root: { level: 'info' }, + }) + ); + + system.setContextConfig(['tests', 'child'], { + appenders: new Map([ + [ + 'custom', + { kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } }, + ], + ]), + loggers: [{ context: '', appenders: ['custom'], level: 'debug' }], + }); + + testsLogger.warn('tests log to default!'); + testsChildLogger.error('tests.child log to custom!'); + testsGrandchildLogger.debug('tests.child.grandchild log to custom!'); + + expect(mockConsoleLog).toHaveBeenCalledTimes(3); + // Parent context is unaffected + expect(JSON.parse(mockConsoleLog.mock.calls[0][0])).toMatchObject({ + context: 'tests', + message: 'tests log to default!', + level: 'WARN', + }); + // Customized contexts + expect(mockConsoleLog.mock.calls[1][0]).toMatchInlineSnapshot( + `"[ERROR][tests.child] tests.child log to custom!"` + ); + + expect(mockConsoleLog.mock.calls[2][0]).toMatchInlineSnapshot( + `"[DEBUG][tests.child.grandchild] tests.child.grandchild log to custom!"` + ); +}); + test('custom context configs are applied on subsequent calls to update()', () => { system.setContextConfig(['tests', 'child'], { appenders: new Map([ diff --git a/src/core/server/logging/logging_system.ts b/src/core/server/logging/logging_system.ts index 0bab9534d2d053..8aadab83bf7163 100644 --- a/src/core/server/logging/logging_system.ts +++ b/src/core/server/logging/logging_system.ts @@ -100,7 +100,9 @@ export class LoggingSystem implements LoggerFactory { // Automatically prepend the base context to the logger sub-contexts loggers: contextConfig.loggers.map((l) => ({ ...l, - context: LoggingConfig.getLoggerContext([context, l.context]), + context: LoggingConfig.getLoggerContext( + l.context.length > 0 ? [context, l.context] : [context] + ), })), }); diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.mocks.ts b/src/core/server/plugins/discovery/plugins_discovery.test.mocks.ts index d92465e4dd4971..83accc06cb9956 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.test.mocks.ts +++ b/src/core/server/plugins/discovery/plugins_discovery.test.mocks.ts @@ -17,14 +17,5 @@ * under the License. */ -export const mockReaddir = jest.fn(); -export const mockReadFile = jest.fn(); -export const mockStat = jest.fn(); -jest.mock('fs', () => ({ - readdir: mockReaddir, - readFile: mockReadFile, - stat: mockStat, -})); - export const mockPackage = new Proxy({ raw: {} as any }, { get: (obj, prop) => obj.raw[prop] }); jest.mock('../../../../../package.json', () => mockPackage); diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.ts b/src/core/server/plugins/discovery/plugins_discovery.test.ts index 1c42f5dcfc7a70..70413757de9da2 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.test.ts +++ b/src/core/server/plugins/discovery/plugins_discovery.test.ts @@ -17,251 +17,384 @@ * under the License. */ -import { mockPackage, mockReaddir, mockReadFile, mockStat } from './plugins_discovery.test.mocks'; -import { rawConfigServiceMock } from '../../config/raw_config_service.mock'; +import { mockPackage } from './plugins_discovery.test.mocks'; +import mockFs from 'mock-fs'; import { loggingSystemMock } from '../../logging/logging_system.mock'; -import { resolve } from 'path'; import { first, map, toArray } from 'rxjs/operators'; - +import { resolve } from 'path'; import { ConfigService, Env } from '../../config'; import { getEnvOptions } from '../../config/__mocks__/env'; -import { PluginWrapper } from '../plugin'; import { PluginsConfig, PluginsConfigType, config } from '../plugins_config'; import { discover } from './plugins_discovery'; +import { rawConfigServiceMock } from '../../config/raw_config_service.mock'; +import { CoreContext } from '../../core_context'; -const TEST_PLUGIN_SEARCH_PATHS = { - nonEmptySrcPlugins: resolve(process.cwd(), 'src', 'plugins'), - emptyPlugins: resolve(process.cwd(), 'plugins'), - nonExistentKibanaExtra: resolve(process.cwd(), '..', 'kibana-extra'), +const KIBANA_ROOT = process.cwd(); + +const Plugins = { + invalid: () => ({ + 'kibana.json': 'not-json', + }), + incomplete: () => ({ + 'kibana.json': JSON.stringify({ version: '1' }), + }), + incompatible: () => ({ + 'kibana.json': JSON.stringify({ id: 'plugin', version: '1' }), + }), + missingManifest: () => ({}), + inaccessibleManifest: () => ({ + 'kibana.json': mockFs.file({ + mode: 0, // 0000, + content: JSON.stringify({ id: 'plugin', version: '1' }), + }), + }), + valid: (id: string) => ({ + 'kibana.json': JSON.stringify({ + id, + configPath: ['plugins', id], + version: '1', + kibanaVersion: '1.2.3', + requiredPlugins: [], + optionalPlugins: [], + server: true, + }), + }), +}; + +const packageMock = { + branch: 'master', + version: '1.2.3', + build: { + distributable: true, + number: 1, + sha: '', + }, }; -const TEST_EXTRA_PLUGIN_PATH = resolve(process.cwd(), 'my-extra-plugin'); - -const logger = loggingSystemMock.create(); - -beforeEach(() => { - mockReaddir.mockImplementation((path, cb) => { - if (path === TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins) { - cb(null, [ - '1', - '2-no-manifest', - '3', - '4-incomplete-manifest', - '5-invalid-manifest', - '6', - '7-non-dir', - '8-incompatible-manifest', - '9-inaccessible-dir', - ]); - } else if (path === TEST_PLUGIN_SEARCH_PATHS.nonExistentKibanaExtra) { - cb(new Error('ENOENT')); - } else { - cb(null, []); - } + +const manifestPath = (...pluginPath: string[]) => + resolve(KIBANA_ROOT, 'src', 'plugins', ...pluginPath, 'kibana.json'); + +describe('plugins discovery system', () => { + let logger: ReturnType; + let env: Env; + let configService: ConfigService; + let pluginConfig: PluginsConfigType; + let coreContext: CoreContext; + + beforeEach(async () => { + logger = loggingSystemMock.create(); + + mockPackage.raw = packageMock; + + env = Env.createDefault( + getEnvOptions({ + cliArgs: { envName: 'development' }, + }) + ); + + configService = new ConfigService( + rawConfigServiceMock.create({ rawConfig: { plugins: { paths: [] } } }), + env, + logger + ); + await configService.setSchema(config.path, config.schema); + + coreContext = { + coreId: Symbol(), + configService, + env, + logger, + }; + + pluginConfig = await configService + .atPath('plugins') + .pipe(first()) + .toPromise(); + + // jest relies on the filesystem to get sourcemaps when using console.log + // which breaks with the mocked FS, see https://github.com/tschaub/mock-fs/issues/234 + // hijacking logging to process.stdout as a workaround for this suite. + jest.spyOn(console, 'log').mockImplementation((...args) => { + process.stdout.write(args + '\n'); + }); }); - mockStat.mockImplementation((path, cb) => { - if (path.includes('9-inaccessible-dir')) { - cb(new Error(`ENOENT (disappeared between "readdir" and "stat").`)); - } else { - cb(null, { isDirectory: () => !path.includes('non-dir') }); - } + afterEach(() => { + mockFs.restore(); + // restore the console.log behavior + jest.restoreAllMocks(); }); - mockReadFile.mockImplementation((path, cb) => { - if (path.includes('no-manifest')) { - cb(new Error('ENOENT')); - } else if (path.includes('invalid-manifest')) { - cb(null, Buffer.from('not-json')); - } else if (path.includes('incomplete-manifest')) { - cb(null, Buffer.from(JSON.stringify({ version: '1' }))); - } else if (path.includes('incompatible-manifest')) { - cb(null, Buffer.from(JSON.stringify({ id: 'plugin', version: '1' }))); - } else { - cb( - null, - Buffer.from( - JSON.stringify({ - id: 'plugin', - configPath: ['core', 'config'], - version: '1', - kibanaVersion: '1.2.3', - requiredPlugins: ['a', 'b'], - optionalPlugins: ['c', 'd'], - server: true, - }) - ) - ); - } + it('discovers plugins in the search locations', async () => { + const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins/plugin_a`]: Plugins.valid('pluginA'), + [`${KIBANA_ROOT}/plugins/plugin_b`]: Plugins.valid('pluginB'), + [`${KIBANA_ROOT}/x-pack/plugins/plugin_c`]: Plugins.valid('pluginC'), + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toHaveLength(3); + expect(pluginNames).toEqual(expect.arrayContaining(['pluginA', 'pluginB', 'pluginC'])); }); -}); -afterEach(() => { - jest.clearAllMocks(); -}); + it('return errors when the manifest is invalid or incompatible', async () => { + const { plugin$, error$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins/plugin_a`]: Plugins.invalid(), + [`${KIBANA_ROOT}/src/plugins/plugin_b`]: Plugins.incomplete(), + [`${KIBANA_ROOT}/src/plugins/plugin_c`]: Plugins.incompatible(), + [`${KIBANA_ROOT}/src/plugins/plugin_ad`]: Plugins.missingManifest(), + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + expect(plugins).toHaveLength(0); + + const errors = await error$ + .pipe( + map((error) => error.toString()), + toArray() + ) + .toPromise(); -test('properly iterates through plugin search locations', async () => { - mockPackage.raw = { - branch: 'master', - version: '1.2.3', - build: { - distributable: true, - number: 1, - sha: '', - }, - }; - - const env = Env.createDefault( - getEnvOptions({ - cliArgs: { envName: 'development' }, - }) - ); - const configService = new ConfigService( - rawConfigServiceMock.create({ rawConfig: { plugins: { paths: [TEST_EXTRA_PLUGIN_PATH] } } }), - env, - logger - ); - await configService.setSchema(config.path, config.schema); - - const rawConfig = await configService - .atPath('plugins') - .pipe(first()) - .toPromise(); - const { plugin$, error$ } = discover(new PluginsConfig(rawConfig, env), { - coreId: Symbol(), - configService, - env, - logger, + expect(errors).toEqual( + expect.arrayContaining([ + `Error: Unexpected token o in JSON at position 1 (invalid-manifest, ${manifestPath( + 'plugin_a' + )})`, + `Error: Plugin manifest must contain an "id" property. (invalid-manifest, ${manifestPath( + 'plugin_b' + )})`, + `Error: Plugin "plugin" is only compatible with Kibana version "1", but used Kibana version is "1.2.3". (incompatible-version, ${manifestPath( + 'plugin_c' + )})`, + ]) + ); }); - const plugins = await plugin$.pipe(toArray()).toPromise(); - expect(plugins).toHaveLength(4); - - for (const path of [ - resolve(TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, '1'), - resolve(TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, '3'), - resolve(TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, '6'), - TEST_EXTRA_PLUGIN_PATH, - ]) { - const discoveredPlugin = plugins.find((plugin) => plugin.path === path)!; - expect(discoveredPlugin).toBeInstanceOf(PluginWrapper); - expect(discoveredPlugin.configPath).toEqual(['core', 'config']); - expect(discoveredPlugin.requiredPlugins).toEqual(['a', 'b']); - expect(discoveredPlugin.optionalPlugins).toEqual(['c', 'd']); - } - - await expect( - error$ + it('return errors when the plugin search path is not accessible', async () => { + const { plugin$, error$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins`]: mockFs.directory({ + mode: 0, // 0000 + items: { + plugin_a: Plugins.valid('pluginA'), + }, + }), + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + expect(plugins).toHaveLength(0); + + const errors = await error$ .pipe( map((error) => error.toString()), toArray() ) - .toPromise() - ).resolves.toEqual([ - `Error: ENOENT (disappeared between "readdir" and "stat"). (invalid-plugin-path, ${resolve( - TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, - '9-inaccessible-dir' - )})`, - `Error: ENOENT (invalid-search-path, ${TEST_PLUGIN_SEARCH_PATHS.nonExistentKibanaExtra})`, - `Error: ENOENT (missing-manifest, ${resolve( - TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, - '2-no-manifest', - 'kibana.json' - )})`, - `Error: Plugin manifest must contain an "id" property. (invalid-manifest, ${resolve( - TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, - '4-incomplete-manifest', - 'kibana.json' - )})`, - `Error: Unexpected token o in JSON at position 1 (invalid-manifest, ${resolve( - TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, - '5-invalid-manifest', - 'kibana.json' - )})`, - `Error: Plugin "plugin" is only compatible with Kibana version "1", but used Kibana version is "1.2.3". (incompatible-version, ${resolve( - TEST_PLUGIN_SEARCH_PATHS.nonEmptySrcPlugins, - '8-incompatible-manifest', - 'kibana.json' - )})`, - ]); -}); + .toPromise(); -test('logs a warning about --plugin-path when used in development', async () => { - mockPackage.raw = { - branch: 'master', - version: '1.2.3', - build: { - distributable: true, - number: 1, - sha: '', - }, - }; - - const env = Env.createDefault( - getEnvOptions({ - cliArgs: { dev: false, envName: 'development' }, - }) - ); - const configService = new ConfigService( - rawConfigServiceMock.create({ rawConfig: { plugins: { paths: [TEST_EXTRA_PLUGIN_PATH] } } }), - env, - logger - ); - await configService.setSchema(config.path, config.schema); - - const rawConfig = await configService - .atPath('plugins') - .pipe(first()) - .toPromise(); - - discover(new PluginsConfig(rawConfig, env), { - coreId: Symbol(), - configService, - env, - logger, + const srcPluginsPath = resolve(KIBANA_ROOT, 'src', 'plugins'); + const xpackPluginsPath = resolve(KIBANA_ROOT, 'x-pack', 'plugins'); + expect(errors).toEqual( + expect.arrayContaining([ + `Error: EACCES, permission denied '${srcPluginsPath}' (invalid-search-path, ${srcPluginsPath})`, + `Error: ENOENT, no such file or directory '${xpackPluginsPath}' (invalid-search-path, ${xpackPluginsPath})`, + ]) + ); }); - expect(loggingSystemMock.collect(logger).warn).toEqual([ - [ - `Explicit plugin paths [${TEST_EXTRA_PLUGIN_PATH}] should only be used in development. Relative imports may not work properly in production.`, - ], - ]); -}); + it('return an error when the manifest file is not accessible', async () => { + const { plugin$, error$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins/plugin_a`]: { + ...Plugins.inaccessibleManifest(), + nested_plugin: Plugins.valid('nestedPlugin'), + }, + }, + { createCwd: false } + ); -test('does not log a warning about --plugin-path when used in production', async () => { - mockPackage.raw = { - branch: 'master', - version: '1.2.3', - build: { - distributable: true, - number: 1, - sha: '', - }, - }; - - const env = Env.createDefault( - getEnvOptions({ - cliArgs: { dev: false, envName: 'production' }, - }) - ); - const configService = new ConfigService( - rawConfigServiceMock.create({ rawConfig: { plugins: { paths: [TEST_EXTRA_PLUGIN_PATH] } } }), - env, - logger - ); - await configService.setSchema(config.path, config.schema); - - const rawConfig = await configService - .atPath('plugins') - .pipe(first()) - .toPromise(); - - discover(new PluginsConfig(rawConfig, env), { - coreId: Symbol(), - configService, - env, - logger, + const plugins = await plugin$.pipe(toArray()).toPromise(); + expect(plugins).toHaveLength(0); + + const errors = await error$ + .pipe( + map((error) => error.toString()), + toArray() + ) + .toPromise(); + + const errorPath = manifestPath('plugin_a'); + expect(errors).toEqual( + expect.arrayContaining([ + `Error: EACCES, permission denied '${errorPath}' (missing-manifest, ${errorPath})`, + ]) + ); + }); + + it('discovers plugins in nested directories', async () => { + const { plugin$, error$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins/plugin_a`]: Plugins.valid('pluginA'), + [`${KIBANA_ROOT}/src/plugins/sub1/plugin_b`]: Plugins.valid('pluginB'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/plugin_c`]: Plugins.valid('pluginC'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/plugin_d`]: Plugins.incomplete(), + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toHaveLength(3); + expect(pluginNames).toEqual(expect.arrayContaining(['pluginA', 'pluginB', 'pluginC'])); + + const errors = await error$ + .pipe( + map((error) => error.toString()), + toArray() + ) + .toPromise(); + + expect(errors).toEqual( + expect.arrayContaining([ + `Error: Plugin manifest must contain an "id" property. (invalid-manifest, ${manifestPath( + 'sub1', + 'sub2', + 'plugin_d' + )})`, + ]) + ); + }); + + it('does not discover plugins nested inside another plugin', async () => { + const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins/plugin_a`]: { + ...Plugins.valid('pluginA'), + nested_plugin: Plugins.valid('nestedPlugin'), + }, + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toEqual(['pluginA']); + }); + + it('stops scanning when reaching `maxDepth`', async () => { + const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + mockFs( + { + [`${KIBANA_ROOT}/src/plugins/sub1/plugin`]: Plugins.valid('plugin1'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/plugin`]: Plugins.valid('plugin2'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/sub3/plugin`]: Plugins.valid('plugin3'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/sub3/sub4/plugin`]: Plugins.valid('plugin4'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/sub3/sub4/sub5/plugin`]: Plugins.valid('plugin5'), + [`${KIBANA_ROOT}/src/plugins/sub1/sub2/sub3/sub4/sub5/sub6/plugin`]: Plugins.valid( + 'plugin6' + ), + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toHaveLength(5); + expect(pluginNames).toEqual( + expect.arrayContaining(['plugin1', 'plugin2', 'plugin3', 'plugin4', 'plugin5']) + ); + }); + + it('works with symlinks', async () => { + const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext); + + const pluginFolder = resolve(KIBANA_ROOT, '..', 'ext-plugins'); + + mockFs( + { + [`${KIBANA_ROOT}/plugins`]: mockFs.symlink({ + path: '../ext-plugins', + }), + [pluginFolder]: { + plugin_a: Plugins.valid('pluginA'), + plugin_b: Plugins.valid('pluginB'), + }, + }, + { createCwd: false } + ); + + const plugins = await plugin$.pipe(toArray()).toPromise(); + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toHaveLength(2); + expect(pluginNames).toEqual(expect.arrayContaining(['pluginA', 'pluginB'])); }); - expect(loggingSystemMock.collect(logger).warn).toEqual([]); + it('logs a warning about --plugin-path when used in development', async () => { + const extraPluginTestPath = resolve(process.cwd(), 'my-extra-plugin'); + + env = Env.createDefault( + getEnvOptions({ + cliArgs: { dev: false, envName: 'development' }, + }) + ); + + discover(new PluginsConfig({ ...pluginConfig, paths: [extraPluginTestPath] }, env), { + coreId: Symbol(), + configService, + env, + logger, + }); + + expect(loggingSystemMock.collect(logger).warn).toEqual([ + [ + `Explicit plugin paths [${extraPluginTestPath}] should only be used in development. Relative imports may not work properly in production.`, + ], + ]); + }); + + test('does not log a warning about --plugin-path when used in production', async () => { + const extraPluginTestPath = resolve(process.cwd(), 'my-extra-plugin'); + + env = Env.createDefault( + getEnvOptions({ + cliArgs: { dev: false, envName: 'production' }, + }) + ); + + discover(new PluginsConfig({ ...pluginConfig, paths: [extraPluginTestPath] }, env), { + coreId: Symbol(), + configService, + env, + logger, + }); + + expect(loggingSystemMock.collect(logger).warn).toEqual([]); + }); }); diff --git a/src/core/server/plugins/discovery/plugins_discovery.ts b/src/core/server/plugins/discovery/plugins_discovery.ts index 1910483211e34c..5e765a9632e55a 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.ts +++ b/src/core/server/plugins/discovery/plugins_discovery.ts @@ -19,7 +19,7 @@ import { readdir, stat } from 'fs'; import { resolve } from 'path'; -import { bindNodeCallback, from, merge } from 'rxjs'; +import { bindNodeCallback, from, merge, Observable } from 'rxjs'; import { catchError, filter, map, mergeMap, shareReplay } from 'rxjs/operators'; import { CoreContext } from '../../core_context'; import { Logger } from '../../logging'; @@ -32,6 +32,13 @@ import { parseManifest } from './plugin_manifest_parser'; const fsReadDir$ = bindNodeCallback(readdir); const fsStat$ = bindNodeCallback(stat); +const maxScanDepth = 5; + +interface PluginSearchPathEntry { + dir: string; + depth: number; +} + /** * Tries to discover all possible plugins based on the provided plugin config. * Discovery result consists of two separate streams, the one (`plugin$`) is @@ -75,34 +82,96 @@ export function discover(config: PluginsConfig, coreContext: CoreContext) { } /** - * Iterates over every plugin search path and returns a merged stream of all - * sub-directories. If directory cannot be read or it's impossible to get stat + * Recursively iterates over every plugin search path and returns a merged stream of all + * sub-directories containing a manifest file. If directory cannot be read or it's impossible to get stat * for any of the nested entries then error is added into the stream instead. + * * @param pluginDirs List of the top-level directories to process. * @param log Plugin discovery logger instance. */ -function processPluginSearchPaths$(pluginDirs: readonly string[], log: Logger) { - return from(pluginDirs).pipe( - mergeMap((dir) => { - log.debug(`Scanning "${dir}" for plugin sub-directories...`); +function processPluginSearchPaths$( + pluginDirs: readonly string[], + log: Logger +): Observable { + function recursiveScanFolder( + ent: PluginSearchPathEntry + ): Observable { + return from([ent]).pipe( + mergeMap((entry) => { + return findManifestInFolder(entry.dir, () => { + if (entry.depth > maxScanDepth) { + return []; + } + return mapSubdirectories(entry.dir, (subDir) => + recursiveScanFolder({ dir: subDir, depth: entry.depth + 1 }) + ); + }); + }) + ); + } - return fsReadDir$(dir).pipe( - mergeMap((subDirs: string[]) => subDirs.map((subDir) => resolve(dir, subDir))), - mergeMap((path) => - fsStat$(path).pipe( - // Filter out non-directory entries from target directories, it's expected that - // these directories may contain files (e.g. `README.md` or `package.json`). - // We shouldn't silently ignore the entries we couldn't get stat for though. - mergeMap((pathStat) => (pathStat.isDirectory() ? [path] : [])), - catchError((err) => [PluginDiscoveryError.invalidPluginPath(path, err)]) - ) - ), - catchError((err) => [PluginDiscoveryError.invalidSearchPath(dir, err)]) + return from(pluginDirs.map((dir) => ({ dir, depth: 0 }))).pipe( + mergeMap((entry) => { + log.debug(`Scanning "${entry.dir}" for plugin sub-directories...`); + return fsReadDir$(entry.dir).pipe( + mergeMap(() => recursiveScanFolder(entry)), + catchError((err) => [PluginDiscoveryError.invalidSearchPath(entry.dir, err)]) ); }) ); } +/** + * Attempts to read manifest file in specified directory or calls `notFound` and returns results if not found. For any + * manifest files that cannot be read, a PluginDiscoveryError is added. + * @param dir + * @param notFound + */ +function findManifestInFolder( + dir: string, + notFound: () => never[] | Observable +): string[] | Observable { + return fsStat$(resolve(dir, 'kibana.json')).pipe( + mergeMap((stats) => { + // `kibana.json` exists in given directory, we got a plugin + if (stats.isFile()) { + return [dir]; + } + return []; + }), + catchError((manifestStatError) => { + // did not find manifest. recursively process sub directories until we reach max depth. + if (manifestStatError.code !== 'ENOENT') { + return [PluginDiscoveryError.invalidPluginPath(dir, manifestStatError)]; + } + return notFound(); + }) + ); +} + +/** + * Finds all subdirectories in `dir` and executed `mapFunc` for each one. For any directories that cannot be read, + * a PluginDiscoveryError is added. + * @param dir + * @param mapFunc + */ +function mapSubdirectories( + dir: string, + mapFunc: (subDir: string) => Observable +): Observable { + return fsReadDir$(dir).pipe( + mergeMap((subDirs: string[]) => subDirs.map((subDir) => resolve(dir, subDir))), + mergeMap((subDir) => + fsStat$(subDir).pipe( + mergeMap((pathStat) => (pathStat.isDirectory() ? mapFunc(subDir) : [])), + catchError((subDirStatError) => [ + PluginDiscoveryError.invalidPluginPath(subDir, subDirStatError), + ]) + ) + ) + ); +} + /** * Tries to load and parse the plugin manifest file located at the provided plugin * directory path and produces an error result if it fails to do so or plugin manifest diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index 2ca5c9f6ed3c56..9e86ee22c607bf 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -19,8 +19,8 @@ import { Observable } from 'rxjs'; import { Type } from '@kbn/config-schema'; +import { RecursiveReadonly } from '@kbn/utility-types'; -import { RecursiveReadonly } from 'kibana/public'; import { ConfigPath, EnvironmentMode, PackageInfo, ConfigDeprecationProvider } from '../config'; import { LoggerFactory } from '../logging'; import { KibanaConfigType } from '../kibana_config'; diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index 48b1e12fc187ed..c2d4f49d7ee2ac 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -30,13 +30,13 @@ import { KibanaMigrator, IKibanaMigrator } from './migrations'; import { CoreContext } from '../core_context'; import { LegacyServiceDiscoverPlugins } from '../legacy'; import { - APICaller, + LegacyAPICaller, ElasticsearchServiceStart, - IClusterClient, + ILegacyClusterClient, InternalElasticsearchServiceSetup, } from '../elasticsearch'; import { KibanaConfigType } from '../kibana_config'; -import { migrationsRetryCallCluster } from '../elasticsearch/retry_call_cluster'; +import { migrationsRetryCallCluster } from '../elasticsearch/legacy'; import { SavedObjectsConfigType, SavedObjectsMigrationConfigType, @@ -434,7 +434,7 @@ export class SavedObjectsService await migrator.runMigrations(); } - const createRepository = (callCluster: APICaller, includedHiddenTypes: string[] = []) => { + const createRepository = (callCluster: LegacyAPICaller, includedHiddenTypes: string[] = []) => { return SavedObjectsRepository.createRepository( migrator, this.typeRegistry, @@ -484,7 +484,7 @@ export class SavedObjectsService private createMigrator( kibanaConfig: KibanaConfigType, savedObjectsConfig: SavedObjectsMigrationConfigType, - esClient: IClusterClient, + esClient: ILegacyClusterClient, migrationsRetryDelay?: number ): KibanaMigrator { return new KibanaMigrator({ diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.ts index e57f08aa7a5274..7d1575798c3575 100644 --- a/src/core/server/saved_objects/service/lib/decorate_es_error.ts +++ b/src/core/server/saved_objects/service/lib/decorate_es_error.ts @@ -26,11 +26,11 @@ const { NoConnections, RequestTimeout, Conflict, - // @ts-ignore + // @ts-expect-error 401: NotAuthorized, - // @ts-ignore + // @ts-expect-error 403: Forbidden, - // @ts-ignore + // @ts-expect-error 413: RequestEntityTooLarge, NotFound, BadRequest, diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 40c5282a77e499..f24195c0f295e3 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -19,8 +19,8 @@ import { omit } from 'lodash'; import uuid from 'uuid'; -import { retryCallCluster } from '../../../elasticsearch/retry_call_cluster'; -import { APICaller } from '../../../elasticsearch/'; +import { retryCallCluster } from '../../../elasticsearch/legacy'; +import { LegacyAPICaller } from '../../../elasticsearch/'; import { getRootPropertiesObjects, IndexMapping } from '../../mappings'; import { getSearchDsl } from './search_dsl'; @@ -74,7 +74,7 @@ const isRight = (either: Either): either is Right => either.tag === 'Right'; export interface SavedObjectsRepositoryOptions { index: string; mappings: IndexMapping; - callCluster: APICaller; + callCluster: LegacyAPICaller; typeRegistry: SavedObjectTypeRegistry; serializer: SavedObjectsSerializer; migrator: KibanaMigrator; @@ -117,7 +117,7 @@ export class SavedObjectsRepository { private _mappings: IndexMapping; private _registry: SavedObjectTypeRegistry; private _allowedTypes: string[]; - private _unwrappedCallCluster: APICaller; + private _unwrappedCallCluster: LegacyAPICaller; private _serializer: SavedObjectsSerializer; /** @@ -132,7 +132,7 @@ export class SavedObjectsRepository { migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, - callCluster: APICaller, + callCluster: LegacyAPICaller, includedHiddenTypes: string[] = [], injectedConstructor: any = SavedObjectsRepository ): ISavedObjectsRepository { @@ -188,7 +188,7 @@ export class SavedObjectsRepository { } this._allowedTypes = allowedTypes; - this._unwrappedCallCluster = async (...args: Parameters) => { + this._unwrappedCallCluster = async (...args: Parameters) => { await migrator.runMigrations(); return callCluster(...args); }; @@ -1300,7 +1300,7 @@ export class SavedObjectsRepository { }; } - private async _writeToCluster(...args: Parameters) { + private async _writeToCluster(...args: Parameters) { try { return await this._callCluster(...args); } catch (err) { @@ -1308,7 +1308,7 @@ export class SavedObjectsRepository { } } - private async _callCluster(...args: Parameters) { + private async _callCluster(...args: Parameters) { try { return await this._unwrappedCallCluster(...args); } catch (err) { diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 108826ad61aa26..9cc5a8a386b0b6 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -108,7 +108,7 @@ import { PingParams } from 'elasticsearch'; import { PutScriptParams } from 'elasticsearch'; import { PutTemplateParams } from 'elasticsearch'; import { Readable } from 'stream'; -import { RecursiveReadonly as RecursiveReadonly_2 } from 'kibana/public'; +import { RecursiveReadonly } from '@kbn/utility-types'; import { ReindexParams } from 'elasticsearch'; import { ReindexRethrottleParams } from 'elasticsearch'; import { RenderSearchTemplateParams } from 'elasticsearch'; @@ -144,250 +144,6 @@ import { UpdateDocumentByQueryParams } from 'elasticsearch'; import { UpdateDocumentParams } from 'elasticsearch'; import { Url } from 'url'; -// @public (undocumented) -export interface APICaller { - // (undocumented) - (endpoint: 'bulk', params: BulkIndexDocumentsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'clearScroll', params: ClearScrollParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'count', params: CountParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'create', params: CreateDocumentParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'delete', params: DeleteDocumentParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'deleteByQuery', params: DeleteDocumentByQueryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'deleteScript', params: DeleteScriptParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'deleteTemplate', params: DeleteTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'exists', params: ExistsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'explain', params: ExplainParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'fieldStats', params: FieldStatsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'get', params: GetParams, options?: CallAPIOptions): Promise>; - // (undocumented) - (endpoint: 'getScript', params: GetScriptParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'getSource', params: GetSourceParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'getTemplate', params: GetTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'index', params: IndexDocumentParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'info', params: InfoParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'mget', params: MGetParams, options?: CallAPIOptions): Promise>; - // (undocumented) - (endpoint: 'msearch', params: MSearchParams, options?: CallAPIOptions): Promise>; - // (undocumented) - (endpoint: 'msearchTemplate', params: MSearchTemplateParams, options?: CallAPIOptions): Promise>; - // (undocumented) - (endpoint: 'mtermvectors', params: MTermVectorsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'ping', params: PingParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'putScript', params: PutScriptParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'putTemplate', params: PutTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'reindex', params: ReindexParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'reindexRethrottle', params: ReindexRethrottleParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'renderSearchTemplate', params: RenderSearchTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'scroll', params: ScrollParams, options?: CallAPIOptions): Promise>; - // (undocumented) - (endpoint: 'search', params: SearchParams, options?: CallAPIOptions): Promise>; - // (undocumented) - (endpoint: 'searchShards', params: SearchShardsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'searchTemplate', params: SearchTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'suggest', params: SuggestParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'termvectors', params: TermvectorsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'update', params: UpdateDocumentParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'updateByQuery', params: UpdateDocumentByQueryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.aliases', params: CatAliasesParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.allocation', params: CatAllocationParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.count', params: CatAllocationParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.fielddata', params: CatFielddataParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.health', params: CatHealthParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.help', params: CatHelpParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.indices', params: CatIndicesParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.master', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.nodeattrs', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.nodes', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.pendingTasks', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.plugins', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.recovery', params: CatRecoveryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.repositories', params: CatCommonParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.segments', params: CatSegmentsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.shards', params: CatShardsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.snapshots', params: CatSnapshotsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.tasks', params: CatTasksParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cat.threadPool', params: CatThreadPoolParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.allocationExplain', params: ClusterAllocationExplainParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.getSettings', params: ClusterGetSettingsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.health', params: ClusterHealthParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.pendingTasks', params: ClusterPendingTasksParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.putSettings', params: ClusterPutSettingsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.reroute', params: ClusterRerouteParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.state', params: ClusterStateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'cluster.stats', params: ClusterStatsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.analyze', params: IndicesAnalyzeParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.clearCache', params: IndicesClearCacheParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.close', params: IndicesCloseParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.create', params: IndicesCreateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.delete', params: IndicesDeleteParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.deleteAlias', params: IndicesDeleteAliasParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.deleteTemplate', params: IndicesDeleteTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.exists', params: IndicesExistsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.existsAlias', params: IndicesExistsAliasParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.existsTemplate', params: IndicesExistsTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.existsType', params: IndicesExistsTypeParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.flush', params: IndicesFlushParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.flushSynced', params: IndicesFlushSyncedParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.forcemerge', params: IndicesForcemergeParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.get', params: IndicesGetParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.getAlias', params: IndicesGetAliasParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.getFieldMapping', params: IndicesGetFieldMappingParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.getMapping', params: IndicesGetMappingParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.getSettings', params: IndicesGetSettingsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.getTemplate', params: IndicesGetTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.getUpgrade', params: IndicesGetUpgradeParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.open', params: IndicesOpenParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.putAlias', params: IndicesPutAliasParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.putMapping', params: IndicesPutMappingParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.putSettings', params: IndicesPutSettingsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.putTemplate', params: IndicesPutTemplateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.recovery', params: IndicesRecoveryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.refresh', params: IndicesRefreshParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.rollover', params: IndicesRolloverParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.segments', params: IndicesSegmentsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.shardStores', params: IndicesShardStoresParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.shrink', params: IndicesShrinkParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.stats', params: IndicesStatsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.updateAliases', params: IndicesUpdateAliasesParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.upgrade', params: IndicesUpgradeParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'indices.validateQuery', params: IndicesValidateQueryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'ingest.deletePipeline', params: IngestDeletePipelineParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'ingest.getPipeline', params: IngestGetPipelineParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'ingest.putPipeline', params: IngestPutPipelineParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'ingest.simulate', params: IngestSimulateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'nodes.hotThreads', params: NodesHotThreadsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'nodes.info', params: NodesInfoParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'nodes.stats', params: NodesStatsParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.create', params: SnapshotCreateParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.createRepository', params: SnapshotCreateRepositoryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.delete', params: SnapshotDeleteParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.deleteRepository', params: SnapshotDeleteRepositoryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.get', params: SnapshotGetParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.getRepository', params: SnapshotGetRepositoryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.restore', params: SnapshotRestoreParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.status', params: SnapshotStatusParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'snapshot.verifyRepository', params: SnapshotVerifyRepositoryParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'tasks.cancel', params: TasksCancelParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'tasks.get', params: TasksGetParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'tasks.list', params: TasksListParams, options?: CallAPIOptions): ReturnType; - // (undocumented) - (endpoint: 'transport.request', clientParams: AssistantAPIClientParams, options?: CallAPIOptions): Promise; - // (undocumented) - (endpoint: 'transport.request', clientParams: DeprecationAPIClientParams, options?: CallAPIOptions): Promise; - // (undocumented) - (endpoint: string, clientParams?: Record, options?: CallAPIOptions): Promise; -} - // Warning: (ae-forgotten-export) The symbol "appendersSchema" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -497,12 +253,6 @@ export class BasePath { // @internal (undocumented) export function bootstrap({ configs, cliArgs, applyConfigOverrides, features, }: BootstrapArgs): Promise; -// @public -export interface CallAPIOptions { - signal?: AbortSignal; - wrap401Errors?: boolean; -} - // @public export interface Capabilities { [key: string]: Record>; @@ -530,14 +280,6 @@ export interface CapabilitiesStart { // @public export type CapabilitiesSwitcher = (request: KibanaRequest, uiCapabilities: Capabilities) => Partial | Promise>; -// @public -export class ClusterClient implements IClusterClient { - constructor(config: ElasticsearchClientConfig, log: Logger, getAuthHeaders?: GetAuthHeaders); - asScoped(request?: ScopeableRequest): IScopedClusterClient; - callAsInternalUser: APICaller; - close(): void; - } - // @alpha export const config: { elasticsearch: { @@ -557,7 +299,7 @@ export const config: { startupTimeout: import("@kbn/config-schema").Type; logQueries: import("@kbn/config-schema").Type; ssl: import("@kbn/config-schema").ObjectType<{ - verificationMode: import("@kbn/config-schema").Type<"none" | "full" | "certificate">; + verificationMode: import("@kbn/config-schema").Type<"none" | "certificate" | "full">; certificateAuthorities: import("@kbn/config-schema").Type; certificate: import("@kbn/config-schema").Type; key: import("@kbn/config-schema").Type; @@ -851,14 +593,6 @@ export interface DiscoveredPlugin { readonly requiredPlugins: readonly PluginName[]; } -// @public (undocumented) -export type ElasticsearchClientConfig = Pick & Pick & { - pingTimeout?: ElasticsearchConfig['pingTimeout'] | ConfigOptions['pingTimeout']; - requestTimeout?: ElasticsearchConfig['requestTimeout'] | ConfigOptions['requestTimeout']; - sniffInterval?: ElasticsearchConfig['sniffInterval'] | ConfigOptions['sniffInterval']; - ssl?: Partial; -}; - // @public export class ElasticsearchConfig { constructor(rawConfig: ElasticsearchConfigType); @@ -884,26 +618,12 @@ export class ElasticsearchConfig { readonly username?: string; } -// @public (undocumented) -export interface ElasticsearchError extends Boom { - // (undocumented) - [code]?: string; -} - -// @public -export class ElasticsearchErrorHelpers { - // (undocumented) - static decorateNotAuthorizedError(error: Error, reason?: string): ElasticsearchError; - // (undocumented) - static isNotAuthorizedError(error: any): error is ElasticsearchError; -} - // @public (undocumented) export interface ElasticsearchServiceSetup { // @deprecated (undocumented) legacy: { - readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; - readonly client: IClusterClient; + readonly createClient: (type: string, clientConfig?: Partial) => ILegacyCustomClusterClient; + readonly client: ILegacyClusterClient; }; } @@ -911,8 +631,8 @@ export interface ElasticsearchServiceSetup { export interface ElasticsearchServiceStart { // @deprecated (undocumented) legacy: { - readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; - readonly client: IClusterClient; + readonly createClient: (type: string, clientConfig?: Partial) => ILegacyCustomClusterClient; + readonly client: ILegacyClusterClient; }; } @@ -1056,9 +776,6 @@ export interface HttpServiceStart { // @public export type IBasePath = Pick; -// @public -export type IClusterClient = Pick; - // @public export interface IContextContainer> { createHandler(pluginOpaqueId: PluginOpaqueId, handler: THandler): (...rest: HandlerParameters) => ShallowPromise>; @@ -1078,9 +795,6 @@ export interface ICspConfig { readonly warnLegacyBrowsers: boolean; } -// @public -export type ICustomClusterClient = Pick; - // @public export interface IKibanaResponse { // (undocumented) @@ -1102,6 +816,15 @@ export interface IKibanaSocket { getPeerCertificate(detailed?: boolean): PeerCertificate | DetailedPeerCertificate | null; } +// @public +export type ILegacyClusterClient = Pick; + +// @public +export type ILegacyCustomClusterClient = Pick; + +// @public +export type ILegacyScopedClusterClient = Pick; + // @public (undocumented) export interface ImageValidation { // (undocumented) @@ -1155,9 +878,6 @@ export type ISavedObjectsRepository = Pick; -// @public -export type IScopedClusterClient = Pick; - // @public export function isRelativeUrl(candidatePath: string): boolean; @@ -1247,6 +967,266 @@ export const kibanaResponseFactory: { // @public export type KnownHeaders = KnownKeys; +// @public (undocumented) +export interface LegacyAPICaller { + // (undocumented) + (endpoint: 'bulk', params: BulkIndexDocumentsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'clearScroll', params: ClearScrollParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'count', params: CountParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'create', params: CreateDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'delete', params: DeleteDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'deleteByQuery', params: DeleteDocumentByQueryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'deleteScript', params: DeleteScriptParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'deleteTemplate', params: DeleteTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'exists', params: ExistsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'explain', params: ExplainParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'fieldStats', params: FieldStatsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'get', params: GetParams, options?: LegacyCallAPIOptions): Promise>; + // (undocumented) + (endpoint: 'getScript', params: GetScriptParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'getSource', params: GetSourceParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'getTemplate', params: GetTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'index', params: IndexDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'info', params: InfoParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'mget', params: MGetParams, options?: LegacyCallAPIOptions): Promise>; + // (undocumented) + (endpoint: 'msearch', params: MSearchParams, options?: LegacyCallAPIOptions): Promise>; + // (undocumented) + (endpoint: 'msearchTemplate', params: MSearchTemplateParams, options?: LegacyCallAPIOptions): Promise>; + // (undocumented) + (endpoint: 'mtermvectors', params: MTermVectorsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'ping', params: PingParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'putScript', params: PutScriptParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'putTemplate', params: PutTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'reindex', params: ReindexParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'reindexRethrottle', params: ReindexRethrottleParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'renderSearchTemplate', params: RenderSearchTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'scroll', params: ScrollParams, options?: LegacyCallAPIOptions): Promise>; + // (undocumented) + (endpoint: 'search', params: SearchParams, options?: LegacyCallAPIOptions): Promise>; + // (undocumented) + (endpoint: 'searchShards', params: SearchShardsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'searchTemplate', params: SearchTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'suggest', params: SuggestParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'termvectors', params: TermvectorsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'update', params: UpdateDocumentParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'updateByQuery', params: UpdateDocumentByQueryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.aliases', params: CatAliasesParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.allocation', params: CatAllocationParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.count', params: CatAllocationParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.fielddata', params: CatFielddataParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.health', params: CatHealthParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.help', params: CatHelpParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.indices', params: CatIndicesParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.master', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.nodeattrs', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.nodes', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.pendingTasks', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.plugins', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.recovery', params: CatRecoveryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.repositories', params: CatCommonParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.segments', params: CatSegmentsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.shards', params: CatShardsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.snapshots', params: CatSnapshotsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.tasks', params: CatTasksParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cat.threadPool', params: CatThreadPoolParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.allocationExplain', params: ClusterAllocationExplainParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.getSettings', params: ClusterGetSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.health', params: ClusterHealthParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.pendingTasks', params: ClusterPendingTasksParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.putSettings', params: ClusterPutSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.reroute', params: ClusterRerouteParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.state', params: ClusterStateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'cluster.stats', params: ClusterStatsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.analyze', params: IndicesAnalyzeParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.clearCache', params: IndicesClearCacheParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.close', params: IndicesCloseParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.create', params: IndicesCreateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.delete', params: IndicesDeleteParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.deleteAlias', params: IndicesDeleteAliasParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.deleteTemplate', params: IndicesDeleteTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.exists', params: IndicesExistsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.existsAlias', params: IndicesExistsAliasParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.existsTemplate', params: IndicesExistsTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.existsType', params: IndicesExistsTypeParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.flush', params: IndicesFlushParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.flushSynced', params: IndicesFlushSyncedParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.forcemerge', params: IndicesForcemergeParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.get', params: IndicesGetParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.getAlias', params: IndicesGetAliasParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.getFieldMapping', params: IndicesGetFieldMappingParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.getMapping', params: IndicesGetMappingParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.getSettings', params: IndicesGetSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.getTemplate', params: IndicesGetTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.getUpgrade', params: IndicesGetUpgradeParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.open', params: IndicesOpenParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.putAlias', params: IndicesPutAliasParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.putMapping', params: IndicesPutMappingParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.putSettings', params: IndicesPutSettingsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.putTemplate', params: IndicesPutTemplateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.recovery', params: IndicesRecoveryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.refresh', params: IndicesRefreshParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.rollover', params: IndicesRolloverParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.segments', params: IndicesSegmentsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.shardStores', params: IndicesShardStoresParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.shrink', params: IndicesShrinkParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.stats', params: IndicesStatsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.updateAliases', params: IndicesUpdateAliasesParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.upgrade', params: IndicesUpgradeParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'indices.validateQuery', params: IndicesValidateQueryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'ingest.deletePipeline', params: IngestDeletePipelineParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'ingest.getPipeline', params: IngestGetPipelineParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'ingest.putPipeline', params: IngestPutPipelineParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'ingest.simulate', params: IngestSimulateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'nodes.hotThreads', params: NodesHotThreadsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'nodes.info', params: NodesInfoParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'nodes.stats', params: NodesStatsParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.create', params: SnapshotCreateParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.createRepository', params: SnapshotCreateRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.delete', params: SnapshotDeleteParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.deleteRepository', params: SnapshotDeleteRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.get', params: SnapshotGetParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.getRepository', params: SnapshotGetRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.restore', params: SnapshotRestoreParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.status', params: SnapshotStatusParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'snapshot.verifyRepository', params: SnapshotVerifyRepositoryParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'tasks.cancel', params: TasksCancelParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'tasks.get', params: TasksGetParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'tasks.list', params: TasksListParams, options?: LegacyCallAPIOptions): ReturnType; + // (undocumented) + (endpoint: 'transport.request', clientParams: AssistantAPIClientParams, options?: LegacyCallAPIOptions): Promise; + // (undocumented) + (endpoint: 'transport.request', clientParams: DeprecationAPIClientParams, options?: LegacyCallAPIOptions): Promise; + // (undocumented) + (endpoint: string, clientParams?: Record, options?: LegacyCallAPIOptions): Promise; +} + +// @public +export interface LegacyCallAPIOptions { + signal?: AbortSignal; + wrap401Errors?: boolean; +} + +// Warning: (ae-unresolved-inheritdoc-reference) The @inheritDoc reference could not be resolved: The package "kibana" does not have an export "IClusterClient" +// +// @public (undocumented) +export class LegacyClusterClient implements ILegacyClusterClient { + constructor(config: LegacyElasticsearchClientConfig, log: Logger, getAuthHeaders?: GetAuthHeaders); + asScoped(request?: ScopeableRequest): ILegacyScopedClusterClient; + callAsInternalUser: LegacyAPICaller; + close(): void; + } + // @internal @deprecated export interface LegacyConfig { // (undocumented) @@ -1261,6 +1241,28 @@ export interface LegacyConfig { set(config: LegacyVars): void; } +// @public (undocumented) +export type LegacyElasticsearchClientConfig = Pick & Pick & { + pingTimeout?: ElasticsearchConfig['pingTimeout'] | ConfigOptions['pingTimeout']; + requestTimeout?: ElasticsearchConfig['requestTimeout'] | ConfigOptions['requestTimeout']; + sniffInterval?: ElasticsearchConfig['sniffInterval'] | ConfigOptions['sniffInterval']; + ssl?: Partial; +}; + +// @public (undocumented) +export interface LegacyElasticsearchError extends Boom { + // (undocumented) + [code]?: string; +} + +// @public +export class LegacyElasticsearchErrorHelpers { + // (undocumented) + static decorateNotAuthorizedError(error: Error, reason?: string): LegacyElasticsearchError; + // (undocumented) + static isNotAuthorizedError(error: any): error is LegacyElasticsearchError; +} + // Warning: (ae-forgotten-export) The symbol "ILegacyInternals" needs to be exported by the entry point index.d.ts // // @internal @deprecated (undocumented) @@ -1280,6 +1282,15 @@ export class LegacyInternals implements ILegacyInternals { export interface LegacyRequest extends Request { } +// Warning: (ae-unresolved-inheritdoc-reference) The @inheritDoc reference could not be resolved: The package "kibana" does not have an export "IScopedClusterClient" +// +// @public (undocumented) +export class LegacyScopedClusterClient implements ILegacyScopedClusterClient { + constructor(internalAPICaller: LegacyAPICaller, scopedAPICaller: LegacyAPICaller, headers?: Headers | undefined); + callAsCurrentUser(endpoint: string, clientParams?: Record, options?: LegacyCallAPIOptions): Promise; + callAsInternalUser(endpoint: string, clientParams?: Record, options?: LegacyCallAPIOptions): Promise; + } + // Warning: (ae-forgotten-export) The symbol "LegacyPlugins" needs to be exported by the entry point index.d.ts // // @internal @deprecated (undocumented) @@ -1652,13 +1663,6 @@ export interface PluginsServiceStart { // @public export type PublicUiSettingsParams = Omit; -// Warning: (ae-forgotten-export) The symbol "RecursiveReadonlyArray" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export type RecursiveReadonly = T extends (...args: any[]) => any ? T : T extends any[] ? RecursiveReadonlyArray : T extends object ? Readonly<{ - [K in keyof T]: RecursiveReadonly; -}> : T; - // @public export type RedirectResponseOptions = HttpResponseOptions & { headers: { @@ -1679,7 +1683,7 @@ export interface RequestHandlerContext { }; elasticsearch: { legacy: { - client: IScopedClusterClient; + client: ILegacyScopedClusterClient; }; }; uiSettings: { @@ -2323,7 +2327,7 @@ export class SavedObjectsRepository { // Warning: (ae-forgotten-export) The symbol "KibanaMigrator" needs to be exported by the entry point index.d.ts // // @internal - static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, callCluster: APICaller, includedHiddenTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository; + static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, callCluster: LegacyAPICaller, includedHiddenTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository; delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>; deleteByNamespace(namespace: string, options?: SavedObjectsDeleteByNamespaceOptions): Promise; deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<{}>; @@ -2478,13 +2482,6 @@ export type SavedObjectUnsanitizedDoc = SavedObjectDoc & Partial // @public export type ScopeableRequest = KibanaRequest | LegacyRequest | FakeRequest; -// @public -export class ScopedClusterClient implements IScopedClusterClient { - constructor(internalAPICaller: APICaller, scopedAPICaller: APICaller, headers?: Headers | undefined); - callAsCurrentUser(endpoint: string, clientParams?: Record, options?: CallAPIOptions): Promise; - callAsInternalUser(endpoint: string, clientParams?: Record, options?: CallAPIOptions): Promise; - } - // @public export interface ServiceStatus | unknown = unknown> { detail?: string; @@ -2546,7 +2543,7 @@ export interface SessionStorageFactory { } // @public (undocumented) -export type SharedGlobalConfig = RecursiveReadonly_2<{ +export type SharedGlobalConfig = RecursiveReadonly<{ kibana: Pick; elasticsearch: Pick; path: Pick; diff --git a/src/core/server/ui_settings/integration_tests/lib/servers.ts b/src/core/server/ui_settings/integration_tests/lib/servers.ts index 486abd5a0c7908..ea462291059a51 100644 --- a/src/core/server/ui_settings/integration_tests/lib/servers.ts +++ b/src/core/server/ui_settings/integration_tests/lib/servers.ts @@ -25,7 +25,7 @@ import { TestKibanaUtils, TestUtils, } from '../../../../../test_utils/kbn_server'; -import { APICaller } from '../../../elasticsearch/'; +import { LegacyAPICaller } from '../../../elasticsearch/'; import { httpServerMock } from '../../../http/http_server.mocks'; let servers: TestUtils; @@ -37,7 +37,7 @@ let kbnServer: TestKibanaUtils['kbnServer']; interface AllServices { kbnServer: TestKibanaUtils['kbnServer']; savedObjectsClient: SavedObjectsClientContract; - callCluster: APICaller; + callCluster: LegacyAPICaller; uiSettings: IUiSettingsClient; deleteKibanaIndex: typeof deleteKibanaIndex; } @@ -62,7 +62,7 @@ export async function startServers() { kbnServer = kbn.kbnServer; } -async function deleteKibanaIndex(callCluster: APICaller) { +async function deleteKibanaIndex(callCluster: LegacyAPICaller) { const kibanaIndices = await callCluster('cat.indices', { index: '.kibana*', format: 'json' }); const indexNames = kibanaIndices.map((x: any) => x.index); if (!indexNames.length) { diff --git a/src/core/utils/deep_freeze.test.ts b/src/core/utils/deep_freeze.test.ts index b4531d80d02526..58aa9c9b8c92ba 100644 --- a/src/core/utils/deep_freeze.test.ts +++ b/src/core/utils/deep_freeze.test.ts @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - import { deepFreeze } from './deep_freeze'; it('returns the first argument with all original references', () => { @@ -33,7 +32,7 @@ it('returns the first argument with all original references', () => { it('prevents adding properties to argument', () => { const frozen = deepFreeze({}); expect(() => { - // @ts-ignore ts knows this shouldn't be possible, but just making sure + // @ts-expect-error ts knows this shouldn't be possible, but just making sure frozen.foo = true; }).toThrowError(`object is not extensible`); }); @@ -41,7 +40,7 @@ it('prevents adding properties to argument', () => { it('prevents changing properties on argument', () => { const frozen = deepFreeze({ foo: false }); expect(() => { - // @ts-ignore ts knows this shouldn't be possible, but just making sure + // @ts-expect-error ts knows this shouldn't be possible, but just making sure frozen.foo = true; }).toThrowError(`read only property 'foo'`); }); @@ -49,7 +48,7 @@ it('prevents changing properties on argument', () => { it('prevents changing properties on nested children of argument', () => { const frozen = deepFreeze({ foo: { bar: { baz: { box: 1 } } } }); expect(() => { - // @ts-ignore ts knows this shouldn't be possible, but just making sure + // @ts-expect-error ts knows this shouldn't be possible, but just making sure frozen.foo.bar.baz.box = 2; }).toThrowError(`read only property 'box'`); }); @@ -57,7 +56,7 @@ it('prevents changing properties on nested children of argument', () => { it('prevents adding items to a frozen array', () => { const frozen = deepFreeze({ foo: [1] }); expect(() => { - // @ts-ignore ts knows this shouldn't be possible, but just making sure + // @ts-expect-error ts knows this shouldn't be possible, but just making sure frozen.foo.push(2); }).toThrowError(`object is not extensible`); }); @@ -65,7 +64,7 @@ it('prevents adding items to a frozen array', () => { it('prevents reassigning items in a frozen array', () => { const frozen = deepFreeze({ foo: [1] }); expect(() => { - // @ts-ignore ts knows this shouldn't be possible, but just making sure + // @ts-expect-error ts knows this shouldn't be possible, but just making sure frozen.foo[0] = 2; }).toThrowError(`read only property '0'`); }); diff --git a/src/core/utils/deep_freeze.ts b/src/core/utils/deep_freeze.ts index b0f283c60d0fc6..fbc35acb45b0f7 100644 --- a/src/core/utils/deep_freeze.ts +++ b/src/core/utils/deep_freeze.ts @@ -16,19 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - -// if we define this inside RecursiveReadonly TypeScript complains -// eslint-disable-next-line @typescript-eslint/no-empty-interface -interface RecursiveReadonlyArray extends Array> {} - -/** @public */ -export type RecursiveReadonly = T extends (...args: any[]) => any - ? T - : T extends any[] - ? RecursiveReadonlyArray - : T extends object - ? Readonly<{ [K in keyof T]: RecursiveReadonly }> - : T; +import { RecursiveReadonly } from '@kbn/utility-types'; /** @public */ export type Freezable = { [k: string]: any } | any[]; @@ -47,6 +35,5 @@ export function deepFreeze(object: T) { deepFreeze(value); } } - return Object.freeze(object) as RecursiveReadonly; } diff --git a/src/core/utils/integration_tests/__fixtures__/frozen_object_mutation/tsconfig.json b/src/core/utils/integration_tests/__fixtures__/frozen_object_mutation/tsconfig.json deleted file mode 100644 index 12307c46b95fa4..00000000000000 --- a/src/core/utils/integration_tests/__fixtures__/frozen_object_mutation/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "skipLibCheck": true, - "lib": [ - "es2018" - ] - }, - "files": [ - "index.ts" - ] -} diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 18fc7ebaa2af44..da343aa0f0672d 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -43,6 +43,7 @@ export default { 'src/plugins/**/*.{ts,tsx}', '!src/plugins/**/{__test__,__snapshots__,__examples__,mocks,tests}/**/*', '!src/plugins/**/*.d.ts', + '!src/plugins/**/test_helpers/**', 'packages/kbn-ui-framework/src/components/**/*.js', '!packages/kbn-ui-framework/src/components/index.js', '!packages/kbn-ui-framework/src/components/**/*/index.js', @@ -51,6 +52,7 @@ export default { '!packages/kbn-ui-framework/src/services/**/*/index.js', 'src/legacy/core_plugins/**/*.{js,jsx,ts,tsx}', '!src/legacy/core_plugins/**/{__test__,__snapshots__}/**/*', + '!src/legacy/core_plugins/tests_bundle/**', ], moduleNameMapper: { '@elastic/eui$': '/node_modules/@elastic/eui/test-env', diff --git a/src/legacy/core_plugins/elasticsearch/server/lib/cluster.ts b/src/legacy/core_plugins/elasticsearch/server/lib/cluster.ts index a595fffb3c2350..0e7692f6be7555 100644 --- a/src/legacy/core_plugins/elasticsearch/server/lib/cluster.ts +++ b/src/legacy/core_plugins/elasticsearch/server/lib/cluster.ts @@ -19,18 +19,18 @@ import { Request } from 'hapi'; import { errors } from 'elasticsearch'; -import { CallAPIOptions, ClusterClient, FakeRequest } from 'kibana/server'; +import { LegacyCallAPIOptions, LegacyClusterClient, FakeRequest } from 'kibana/server'; export class Cluster { public readonly errors = errors; - constructor(private readonly clusterClient: ClusterClient) {} + constructor(private readonly clusterClient: LegacyClusterClient) {} public callWithRequest = async ( req: Request | FakeRequest, endpoint: string, clientParams?: Record, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) => { return await this.clusterClient .asScoped(req) @@ -40,7 +40,7 @@ export class Cluster { public callWithInternalUser = async ( endpoint: string, clientParams?: Record, - options?: CallAPIOptions + options?: LegacyCallAPIOptions ) => { return await this.clusterClient.callAsInternalUser(endpoint, clientParams, options); }; diff --git a/src/plugins/advanced_settings/public/plugin.ts b/src/plugins/advanced_settings/public/plugin.ts index 2784b74ab726cf..8b3347f8d88f0e 100644 --- a/src/plugins/advanced_settings/public/plugin.ts +++ b/src/plugins/advanced_settings/public/plugin.ts @@ -17,8 +17,8 @@ * under the License. */ import { i18n } from '@kbn/i18n'; -import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { ManagementApp, ManagementSectionId } from '../../management/public'; +import { CoreSetup, Plugin } from 'kibana/public'; +import { ManagementSectionId } from '../../management/public'; import { ComponentRegistry } from './component_registry'; import { AdvancedSettingsSetup, AdvancedSettingsStart, AdvancedSettingsPluginSetup } from './types'; @@ -30,11 +30,10 @@ const title = i18n.translate('advancedSettings.advancedSettingsLabel', { export class AdvancedSettingsPlugin implements Plugin { - private managementApp?: ManagementApp; public setup(core: CoreSetup, { management }: AdvancedSettingsPluginSetup) { const kibanaSection = management.sections.getSection(ManagementSectionId.Kibana); - this.managementApp = kibanaSection.registerApp({ + kibanaSection.registerApp({ id: 'settings', title, order: 3, @@ -51,11 +50,7 @@ export class AdvancedSettingsPlugin }; } - public start(core: CoreStart) { - if (!core.application.capabilities.management.kibana.settings) { - this.managementApp!.disable(); - } - + public start() { return { component: component.start, }; diff --git a/src/plugins/data/common/field_formats/mocks.ts b/src/plugins/data/common/field_formats/mocks.ts index 394d4c383032fb..9bbaefe2d146a8 100644 --- a/src/plugins/data/common/field_formats/mocks.ts +++ b/src/plugins/data/common/field_formats/mocks.ts @@ -17,7 +17,8 @@ * under the License. */ -import { IFieldFormatsRegistry } from '.'; +import { identity } from 'lodash'; +import { FieldFormat, IFieldFormatsRegistry } from '.'; export const fieldFormatsMock: IFieldFormatsRegistry = { getByFieldType: jest.fn(), @@ -35,6 +36,9 @@ export const fieldFormatsMock: IFieldFormatsRegistry = { init: jest.fn(), register: jest.fn(), parseDefaultTypeMap: jest.fn(), - deserialize: jest.fn(), + deserialize: jest.fn().mockImplementation(() => { + const DefaultFieldFormat = FieldFormat.from(identity); + return new DefaultFieldFormat(); + }), getTypeWithoutMetaParams: jest.fn(), }; diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index b40e02b709d301..0fb45fcc739d45 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -26,6 +26,5 @@ export * from './kbn_field_types'; export * from './query'; export * from './search'; export * from './search/aggs'; -export * from './timefilter'; export * from './types'; export * from './utils'; diff --git a/src/plugins/data/common/query/index.ts b/src/plugins/data/common/query/index.ts index 4e90f6f8bb83ec..b0dfbbb82355e0 100644 --- a/src/plugins/data/common/query/index.ts +++ b/src/plugins/data/common/query/index.ts @@ -18,5 +18,6 @@ */ export * from './filter_manager'; +export * from './timefilter'; export * from './types'; export * from './is_query'; diff --git a/src/plugins/data/public/query/timefilter/get_time.test.ts b/src/plugins/data/common/query/timefilter/get_time.test.ts similarity index 100% rename from src/plugins/data/public/query/timefilter/get_time.test.ts rename to src/plugins/data/common/query/timefilter/get_time.test.ts diff --git a/src/plugins/data/public/query/timefilter/get_time.ts b/src/plugins/data/common/query/timefilter/get_time.ts similarity index 90% rename from src/plugins/data/public/query/timefilter/get_time.ts rename to src/plugins/data/common/query/timefilter/get_time.ts index 3706972ce4a2ef..6e4eda95accc73 100644 --- a/src/plugins/data/public/query/timefilter/get_time.ts +++ b/src/plugins/data/common/query/timefilter/get_time.ts @@ -18,14 +18,16 @@ */ import dateMath from '@elastic/datemath'; -import { IIndexPattern } from '../..'; -import { TimeRange, buildRangeFilter } from '../../../common'; +import { buildRangeFilter, IIndexPattern, TimeRange, TimeRangeBounds } from '../..'; interface CalculateBoundsOptions { forceNow?: Date; } -export function calculateBounds(timeRange: TimeRange, options: CalculateBoundsOptions = {}) { +export function calculateBounds( + timeRange: TimeRange, + options: CalculateBoundsOptions = {} +): TimeRangeBounds { return { min: dateMath.parse(timeRange.from, { forceNow: options.forceNow }), max: dateMath.parse(timeRange.to, { roundUp: true, forceNow: options.forceNow }), diff --git a/src/plugins/data/common/timefilter/index.ts b/src/plugins/data/common/query/timefilter/index.ts similarity index 92% rename from src/plugins/data/common/timefilter/index.ts rename to src/plugins/data/common/query/timefilter/index.ts index e0c509e119fda1..55739511a0ef54 100644 --- a/src/plugins/data/common/timefilter/index.ts +++ b/src/plugins/data/common/query/timefilter/index.ts @@ -17,4 +17,5 @@ * under the License. */ -export { isTimeRange } from './is_time_range'; +export * from './get_time'; +export * from './is_time_range'; diff --git a/src/plugins/data/common/timefilter/is_time_range.ts b/src/plugins/data/common/query/timefilter/is_time_range.ts similarity index 100% rename from src/plugins/data/common/timefilter/is_time_range.ts rename to src/plugins/data/common/query/timefilter/is_time_range.ts diff --git a/src/plugins/data/common/timefilter/types.ts b/src/plugins/data/common/query/timefilter/types.ts similarity index 88% rename from src/plugins/data/common/timefilter/types.ts rename to src/plugins/data/common/query/timefilter/types.ts index b197b16e67dd11..60008ce6054e1b 100644 --- a/src/plugins/data/common/timefilter/types.ts +++ b/src/plugins/data/common/query/timefilter/types.ts @@ -17,6 +17,8 @@ * under the License. */ +import { Moment } from 'moment'; + export interface RefreshInterval { pause: boolean; value: number; @@ -27,3 +29,8 @@ export interface TimeRange { to: string; mode?: 'absolute' | 'relative'; } + +export interface TimeRangeBounds { + min: Moment | undefined; + max: Moment | undefined; +} diff --git a/src/plugins/data/common/query/types.ts b/src/plugins/data/common/query/types.ts index 61b5d5b2b7b4ad..6b34a1baf293bc 100644 --- a/src/plugins/data/common/query/types.ts +++ b/src/plugins/data/common/query/types.ts @@ -17,6 +17,8 @@ * under the License. */ +export * from './timefilter/types'; + export interface Query { query: string | { [key: string]: any }; language: string; diff --git a/src/plugins/data/common/types.ts b/src/plugins/data/common/types.ts index 93629c3dbaf626..e2ec1a031b0ca7 100644 --- a/src/plugins/data/common/types.ts +++ b/src/plugins/data/common/types.ts @@ -17,7 +17,6 @@ * under the License. */ -export * from './timefilter/types'; export * from './query/types'; export * from './kbn_field_types/types'; export * from './index_patterns/types'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index efce8d2c021c99..89b0d7e0303b98 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -421,7 +421,6 @@ export { connectToQueryState, syncQueryStateWithUrl, QueryState, - getTime, getQueryLog, getDefaultQuery, FilterManager, @@ -435,6 +434,7 @@ export { } from './query'; export { + getTime, // kbn field types castEsToKbnFieldTypeName, getKbnTypeNames, diff --git a/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx b/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx index e32a8e023cf402..7ed6525db6350e 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx +++ b/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx @@ -30,7 +30,7 @@ export const onRedirectNoIndexPattern = ( navigateToApp: CoreStart['application']['navigateToApp'], overlays: CoreStart['overlays'] ) => () => { - const canManageIndexPatterns = capabilities.management.kibana.index_patterns; + const canManageIndexPatterns = capabilities.management.kibana.indexPatterns; const redirectTarget = canManageIndexPatterns ? '/management/kibana/indexPatterns' : '/home'; let timeoutId: NodeJS.Timeout | undefined; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 493733daf261b2..51f96f10aa7c72 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -146,7 +146,6 @@ export class DataPublicPlugin implements Plugin>; +export const QueryStringInput: React.FC>; // @public (undocumented) export type QuerySuggestion = QuerySuggestionBasic | QuerySuggestionField; diff --git a/src/plugins/data/public/query/timefilter/index.ts b/src/plugins/data/public/query/timefilter/index.ts index a5885a59f60ede..f71061677ceb78 100644 --- a/src/plugins/data/public/query/timefilter/index.ts +++ b/src/plugins/data/public/query/timefilter/index.ts @@ -22,6 +22,5 @@ export { TimefilterService, TimefilterSetup } from './timefilter_service'; export * from './types'; export { Timefilter, TimefilterContract } from './timefilter'; export { TimeHistory, TimeHistoryContract } from './time_history'; -export { getTime, calculateBounds } from './get_time'; export { changeTimeFilter, convertRangeFilterToTimeRangeString } from './lib/change_time_filter'; export { extractTimeFilter } from './lib/extract_time_filter'; diff --git a/src/plugins/kibana_utils/common/default_feedback_message.test.ts b/src/plugins/data/public/query/timefilter/lib/get_force_now.ts similarity index 67% rename from src/plugins/kibana_utils/common/default_feedback_message.test.ts rename to src/plugins/data/public/query/timefilter/lib/get_force_now.ts index 5c1afa4634b71e..fe68656f0c3aaf 100644 --- a/src/plugins/kibana_utils/common/default_feedback_message.test.ts +++ b/src/plugins/data/public/query/timefilter/lib/get_force_now.ts @@ -17,10 +17,18 @@ * under the License. */ -import { defaultFeedbackMessage } from './default_feedback_message'; +import { parseQueryString } from './parse_querystring'; -test('default feedback message with link', () => { - expect(defaultFeedbackMessage).toMatchInlineSnapshot( - `"Have feedback? Please create an issue in GitHub."` - ); -}); +/** @internal */ +export function getForceNow() { + const forceNow = parseQueryString().forceNow as string; + if (!forceNow) { + return; + } + + const ticks = Date.parse(forceNow); + if (isNaN(ticks)) { + throw new Error(`forceNow query parameter, ${forceNow}, can't be parsed by Date.parse`); + } + return new Date(ticks); +} diff --git a/src/plugins/data/public/query/timefilter/lib/parse_querystring.ts b/src/plugins/data/public/query/timefilter/lib/parse_querystring.ts index 2220ad4eef1b7f..5982bfd0bd276d 100644 --- a/src/plugins/data/public/query/timefilter/lib/parse_querystring.ts +++ b/src/plugins/data/public/query/timefilter/lib/parse_querystring.ts @@ -18,6 +18,7 @@ */ import { parse } from 'query-string'; +/** @internal */ export function parseQueryString() { // window.location.search is an empty string // get search from href diff --git a/src/plugins/data/public/query/timefilter/timefilter.ts b/src/plugins/data/public/query/timefilter/timefilter.ts index 86ef69be572a9c..5eb1546fa015f0 100644 --- a/src/plugins/data/public/query/timefilter/timefilter.ts +++ b/src/plugins/data/public/query/timefilter/timefilter.ts @@ -21,10 +21,9 @@ import _ from 'lodash'; import { Subject, BehaviorSubject } from 'rxjs'; import moment from 'moment'; import { areRefreshIntervalsDifferent, areTimeRangesDifferent } from './lib/diff_time_picker_vals'; -import { parseQueryString } from './lib/parse_querystring'; -import { calculateBounds, getTime } from './get_time'; +import { getForceNow } from './lib/get_force_now'; import { TimefilterConfig, InputTimeRange, TimeRangeBounds } from './types'; -import { RefreshInterval, TimeRange } from '../../../common'; +import { calculateBounds, getTime, RefreshInterval, TimeRange } from '../../../common'; import { TimeHistoryContract } from './time_history'; import { IndexPattern } from '../../index_patterns'; @@ -224,16 +223,7 @@ export class Timefilter { } private getForceNow = () => { - const forceNow = parseQueryString().forceNow as string; - if (!forceNow) { - return; - } - - const ticks = Date.parse(forceNow); - if (isNaN(ticks)) { - throw new Error(`forceNow query parameter, ${forceNow}, can't be parsed by Date.parse`); - } - return new Date(ticks); + return getForceNow(); }; } diff --git a/src/plugins/data/public/query/timefilter/types.ts b/src/plugins/data/public/query/timefilter/types.ts index 8b8deea43f808e..d47a9cbb3bd609 100644 --- a/src/plugins/data/public/query/timefilter/types.ts +++ b/src/plugins/data/public/query/timefilter/types.ts @@ -16,7 +16,9 @@ * specific language governing permissions and limitations * under the License. */ + import { Moment } from 'moment'; + import { TimeRange, RefreshInterval } from '../../../common'; export interface TimefilterConfig { @@ -32,7 +34,4 @@ export type InputTimeRange = to: Moment; }; -export interface TimeRangeBounds { - min: Moment | undefined; - max: Moment | undefined; -} +export { TimeRangeBounds } from '../../../common'; diff --git a/src/plugins/data/public/search/aggs/agg_config.test.ts b/src/plugins/data/public/search/aggs/agg_config.test.ts index 95e0b2cd27186b..18a86d767c2de2 100644 --- a/src/plugins/data/public/search/aggs/agg_config.test.ts +++ b/src/plugins/data/public/search/aggs/agg_config.test.ts @@ -25,31 +25,23 @@ import { AggType } from './agg_type'; import { AggTypesRegistryStart } from './agg_types_registry'; import { mockDataServices, mockAggTypesRegistry } from './test_helpers'; import { MetricAggType } from './metrics/metric_agg_type'; -import { - Field as IndexPatternField, - IndexPattern, - IIndexPatternFieldList, -} from '../../index_patterns'; +import { IndexPattern, IIndexPatternFieldList } from '../../index_patterns'; import { stubIndexPatternWithFields } from '../../../public/stubs'; -import { FieldFormatsStart } from '../../field_formats'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; describe('AggConfig', () => { let indexPattern: IndexPattern; let typesRegistry: AggTypesRegistryStart; - let fieldFormats: FieldFormatsStart; beforeEach(() => { jest.restoreAllMocks(); mockDataServices(); - fieldFormats = fieldFormatsServiceMock.createStartContract(); indexPattern = stubIndexPatternWithFields as IndexPattern; typesRegistry = mockAggTypesRegistry(); }); describe('#toDsl', () => { it('calls #write()', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { enabled: true, type: 'date_histogram', @@ -64,7 +56,7 @@ describe('AggConfig', () => { }); it('uses the type name as the agg name', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { enabled: true, type: 'date_histogram', @@ -79,7 +71,7 @@ describe('AggConfig', () => { }); it('uses the params from #write() output as the agg params', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { enabled: true, type: 'date_histogram', @@ -109,7 +101,7 @@ describe('AggConfig', () => { params: {}, }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const histoConfig = ac.byName('date_histogram')[0]; const avgConfig = ac.byName('avg')[0]; @@ -219,8 +211,8 @@ describe('AggConfig', () => { testsIdentical.forEach((configState, index) => { it(`identical aggregations (${index})`, () => { - const ac1 = new AggConfigs(indexPattern, configState, { typesRegistry, fieldFormats }); - const ac2 = new AggConfigs(indexPattern, configState, { typesRegistry, fieldFormats }); + const ac1 = new AggConfigs(indexPattern, configState, { typesRegistry }); + const ac2 = new AggConfigs(indexPattern, configState, { typesRegistry }); expect(ac1.jsonDataEquals(ac2.aggs)).toBe(true); }); }); @@ -260,8 +252,8 @@ describe('AggConfig', () => { testsIdenticalDifferentOrder.forEach((test, index) => { it(`identical aggregations (${index}) - init json is in different order`, () => { - const ac1 = new AggConfigs(indexPattern, test.config1, { typesRegistry, fieldFormats }); - const ac2 = new AggConfigs(indexPattern, test.config2, { typesRegistry, fieldFormats }); + const ac1 = new AggConfigs(indexPattern, test.config1, { typesRegistry }); + const ac2 = new AggConfigs(indexPattern, test.config2, { typesRegistry }); expect(ac1.jsonDataEquals(ac2.aggs)).toBe(true); }); }); @@ -325,8 +317,8 @@ describe('AggConfig', () => { testsDifferent.forEach((test, index) => { it(`different aggregations (${index})`, () => { - const ac1 = new AggConfigs(indexPattern, test.config1, { typesRegistry, fieldFormats }); - const ac2 = new AggConfigs(indexPattern, test.config2, { typesRegistry, fieldFormats }); + const ac1 = new AggConfigs(indexPattern, test.config1, { typesRegistry }); + const ac2 = new AggConfigs(indexPattern, test.config2, { typesRegistry }); expect(ac1.jsonDataEquals(ac2.aggs)).toBe(false); }); }); @@ -334,7 +326,7 @@ describe('AggConfig', () => { describe('#serialize', () => { it('includes the aggs id, params, type and schema', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { enabled: true, type: 'date_histogram', @@ -365,8 +357,8 @@ describe('AggConfig', () => { params: {}, }, ]; - const ac1 = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); - const ac2 = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac1 = new AggConfigs(indexPattern, configStates, { typesRegistry }); + const ac2 = new AggConfigs(indexPattern, configStates, { typesRegistry }); // this relies on the assumption that js-engines consistently loop over properties in insertion order. // most likely the case, but strictly speaking not guaranteed by the JS and JSON specifications. @@ -394,7 +386,7 @@ describe('AggConfig', () => { params: { field: 'machine.os.keyword' }, }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(ac.aggs.map((agg) => agg.toSerializedFieldFormat())).toMatchInlineSnapshot(` Array [ @@ -456,7 +448,7 @@ describe('AggConfig', () => { }, }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(ac.aggs.map((agg) => agg.toSerializedFieldFormat())).toMatchInlineSnapshot(` Array [ @@ -478,20 +470,8 @@ describe('AggConfig', () => { }); describe('#toExpressionAst', () => { - beforeEach(() => { - fieldFormats.getDefaultInstance = (() => ({ - getConverterFor: (t?: string) => t || identity, - })) as any; - indexPattern.fields.getByName = (name) => - ({ - format: { - getConverterFor: (t?: string) => t || identity, - }, - } as IndexPatternField); - }); - it('works with primitive param types', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { enabled: true, type: 'terms', @@ -540,7 +520,7 @@ describe('AggConfig', () => { }); it('creates a subexpression for params of type "agg"', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { type: 'terms', params: { @@ -616,7 +596,7 @@ describe('AggConfig', () => { }, }); - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { type: 'range', params: { @@ -647,7 +627,7 @@ describe('AggConfig', () => { }); it('stringifies any other params which are an object', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { type: 'terms', params: { @@ -662,7 +642,7 @@ describe('AggConfig', () => { }); it(`returns undefined if an expressionName doesn't exist on the agg type`, () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); const configStates = { type: 'unknown type', params: {}, @@ -676,7 +656,7 @@ describe('AggConfig', () => { let aggConfig: AggConfig; beforeEach(() => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, [], { typesRegistry }); aggConfig = ac.createAggConfig({ type: 'count' } as CreateAggConfigParams); }); @@ -702,85 +682,4 @@ describe('AggConfig', () => { expect(label).toBe(''); }); }); - - describe('#fieldFormatter - custom getFormat handler', () => { - it('returns formatter from getFormat handler', () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry, fieldFormats }); - const configStates = { - enabled: true, - type: 'count', - schema: 'metric', - params: { field: '@timestamp' }, - }; - const aggConfig = ac.createAggConfig(configStates); - - const fieldFormatter = aggConfig.fieldFormatter(); - expect(fieldFormatter).toBeDefined(); - expect(fieldFormatter('text')).toBe('text'); - }); - }); - - // TODO: Converting these field formatter tests from browser tests to unit - // tests makes them much less helpful due to the extensive use of mocking. - // We should revisit these and rewrite them into something more useful. - describe('#fieldFormatter - no custom getFormat handler', () => { - let aggConfig: AggConfig; - - beforeEach(() => { - fieldFormats.getDefaultInstance = (() => ({ - getConverterFor: (t?: string) => t || identity, - })) as any; - indexPattern.fields.getByName = (name) => - ({ - format: { - getConverterFor: (t?: string) => t || identity, - }, - } as IndexPatternField); - - const configStates = { - enabled: true, - type: 'histogram', - schema: 'bucket', - params: { - field: 'bytes', - }, - }; - const ac = new AggConfigs(indexPattern, [configStates], { typesRegistry, fieldFormats }); - aggConfig = ac.createAggConfig(configStates); - }); - - it("returns the field's formatter", () => { - aggConfig.params.field = { - format: { - getConverterFor: (t?: string) => t || identity, - }, - }; - expect(aggConfig.fieldFormatter().toString()).toBe( - aggConfig.getField().format.getConverterFor().toString() - ); - }); - - it('returns the string format if the field does not have a format', () => { - const agg = aggConfig; - agg.params.field = { type: 'number', format: null }; - const fieldFormatter = agg.fieldFormatter(); - expect(fieldFormatter).toBeDefined(); - expect(fieldFormatter('text')).toBe('text'); - }); - - it('returns the string format if there is no field', () => { - const agg = aggConfig; - delete agg.params.field; - const fieldFormatter = agg.fieldFormatter(); - expect(fieldFormatter).toBeDefined(); - expect(fieldFormatter('text')).toBe('text'); - }); - - it('returns the html converter if "html" is passed in', () => { - const field = indexPattern.fields.getByName('bytes'); - expect(aggConfig.fieldFormatter('html').toString()).toBe( - field!.format.getConverterFor('html').toString() - ); - }); - }); }); diff --git a/src/plugins/data/public/search/aggs/agg_config.ts b/src/plugins/data/public/search/aggs/agg_config.ts index a2b74eca584766..8650f5920e5202 100644 --- a/src/plugins/data/public/search/aggs/agg_config.ts +++ b/src/plugins/data/public/search/aggs/agg_config.ts @@ -30,8 +30,6 @@ import { writeParams } from './agg_params'; import { IAggConfigs } from './agg_configs'; import { FetchOptions } from '../fetch'; import { ISearchSource } from '../search_source'; -import { FieldFormatsContentType, KBN_FIELD_TYPES } from '../../../common'; -import { FieldFormatsStart } from '../../field_formats'; type State = string | number | boolean | null | undefined | SerializableState; @@ -52,10 +50,6 @@ export type AggConfigSerialized = Ensure< SerializableState >; -export interface AggConfigDependencies { - fieldFormats: FieldFormatsStart; -} - export type AggConfigOptions = Assign; /** @@ -116,13 +110,8 @@ export class AggConfig { private __type: IAggType; private __typeDecorations: any; private subAggs: AggConfig[] = []; - private readonly fieldFormats: FieldFormatsStart; - constructor( - aggConfigs: IAggConfigs, - opts: AggConfigOptions, - { fieldFormats }: AggConfigDependencies - ) { + constructor(aggConfigs: IAggConfigs, opts: AggConfigOptions) { this.aggConfigs = aggConfigs; this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; @@ -143,8 +132,6 @@ export class AggConfig { // @ts-ignore this.__type = this.__type; - - this.fieldFormats = fieldFormats; } /** @@ -433,24 +420,6 @@ export class AggConfig { return this.aggConfigs.timeRange; } - fieldFormatter(contentType?: FieldFormatsContentType, defaultFormat?: any) { - const format = this.type && this.type.getFormat(this); - - if (format) { - return format.getConverterFor(contentType); - } - - return this.fieldOwnFormatter(contentType, defaultFormat); - } - - fieldOwnFormatter(contentType?: FieldFormatsContentType, defaultFormat?: any) { - const field = this.getField(); - let format = field && field.format; - if (!format) format = defaultFormat; - if (!format) format = this.fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); - return format.getConverterFor(contentType); - } - fieldName() { const field = this.getField(); return field ? field.name : ''; diff --git a/src/plugins/data/public/search/aggs/agg_configs.test.ts b/src/plugins/data/public/search/aggs/agg_configs.test.ts index 6e6fb3350d901f..121bb29f6f8edb 100644 --- a/src/plugins/data/public/search/aggs/agg_configs.test.ts +++ b/src/plugins/data/public/search/aggs/agg_configs.test.ts @@ -24,12 +24,10 @@ import { AggTypesRegistryStart } from './agg_types_registry'; import { mockDataServices, mockAggTypesRegistry } from './test_helpers'; import { Field as IndexPatternField, IndexPattern } from '../../index_patterns'; import { stubIndexPattern, stubIndexPatternWithFields } from '../../../public/stubs'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; describe('AggConfigs', () => { let indexPattern: IndexPattern; let typesRegistry: AggTypesRegistryStart; - const fieldFormats = fieldFormatsServiceMock.createStartContract(); beforeEach(() => { mockDataServices(); @@ -47,7 +45,7 @@ describe('AggConfigs', () => { }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(ac.aggs).toHaveLength(1); }); @@ -72,7 +70,7 @@ describe('AggConfigs', () => { ]; const spy = jest.spyOn(AggConfig, 'ensureIds'); - new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(spy).toHaveBeenCalledTimes(1); expect(spy.mock.calls[0]).toEqual([configStates]); spy.mockRestore(); @@ -94,20 +92,16 @@ describe('AggConfigs', () => { }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(ac.aggs).toHaveLength(2); ac.createAggConfig( - new AggConfig( - ac, - { - enabled: true, - type: typesRegistry.get('terms'), - params: {}, - schema: 'split', - }, - { fieldFormats } - ) + new AggConfig(ac, { + enabled: true, + type: typesRegistry.get('terms'), + params: {}, + schema: 'split', + }) ); expect(ac.aggs).toHaveLength(3); }); @@ -121,7 +115,7 @@ describe('AggConfigs', () => { }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(ac.aggs).toHaveLength(1); ac.createAggConfig({ @@ -142,7 +136,7 @@ describe('AggConfigs', () => { }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); expect(ac.aggs).toHaveLength(1); ac.createAggConfig( @@ -170,7 +164,7 @@ describe('AggConfigs', () => { { type: 'percentiles', enabled: true, params: {}, schema: 'metric' }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const sorted = ac.getRequestAggs(); const aggs = indexBy(ac.aggs, (agg) => agg.type.name); @@ -193,7 +187,7 @@ describe('AggConfigs', () => { { type: 'count', enabled: true, params: {}, schema: 'metric' }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const sorted = ac.getResponseAggs(); const aggs = indexBy(ac.aggs, (agg) => agg.type.name); @@ -210,7 +204,7 @@ describe('AggConfigs', () => { { type: 'percentiles', enabled: true, params: { percents: [1, 2, 3] }, schema: 'metric' }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const sorted = ac.getResponseAggs(); const aggs = indexBy(ac.aggs, (agg) => agg.type.name); @@ -231,7 +225,7 @@ describe('AggConfigs', () => { it('uses the sorted aggs', () => { const configStates = [{ enabled: true, type: 'avg', params: { field: 'bytes' } }]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const spy = jest.spyOn(AggConfigs.prototype, 'getRequestAggs'); ac.toDsl(); expect(spy).toHaveBeenCalledTimes(1); @@ -245,10 +239,7 @@ describe('AggConfigs', () => { { enabled: true, type: 'count', params: {} }, ]; - const ac = new AggConfigs(indexPattern, configStates, { - typesRegistry, - fieldFormats, - }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const aggInfos = ac.aggs.map((aggConfig) => { const football = {}; @@ -291,7 +282,7 @@ describe('AggConfigs', () => { }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const dsl = ac.toDsl(); const histo = ac.byName('date_histogram')[0]; const count = ac.byName('count')[0]; @@ -316,10 +307,7 @@ describe('AggConfigs', () => { { enabled: true, type: 'max', schema: 'metric', params: { field: 'bytes' } }, ]; - const ac = new AggConfigs(indexPattern, configStates, { - typesRegistry, - fieldFormats, - }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const dsl = ac.toDsl(); const histo = ac.byName('date_histogram')[0]; const metrics = ac.bySchemaName('metrics'); @@ -344,7 +332,7 @@ describe('AggConfigs', () => { { enabled: true, type: 'max', schema: 'metric', params: { field: 'bytes' } }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const topLevelDsl = ac.toDsl(true); const buckets = ac.bySchemaName('buckets'); const metrics = ac.bySchemaName('metrics'); @@ -414,7 +402,7 @@ describe('AggConfigs', () => { }, ]; - const ac = new AggConfigs(indexPattern, configStates, { typesRegistry, fieldFormats }); + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); const topLevelDsl = ac.toDsl(true)['2']; expect(Object.keys(topLevelDsl.aggs)).toContain('1'); diff --git a/src/plugins/data/public/search/aggs/agg_configs.ts b/src/plugins/data/public/search/aggs/agg_configs.ts index 6cc03be292d7b5..b272dfd3c7468e 100644 --- a/src/plugins/data/public/search/aggs/agg_configs.ts +++ b/src/plugins/data/public/search/aggs/agg_configs.ts @@ -28,7 +28,6 @@ import { IndexPattern } from '../../index_patterns'; import { ISearchSource } from '../search_source'; import { FetchOptions } from '../fetch'; import { TimeRange } from '../../../common'; -import { FieldFormatsStart } from '../../field_formats'; function removeParentAggs(obj: any) { for (const prop in obj) { @@ -48,7 +47,6 @@ function parseParentAggs(dslLvlCursor: any, dsl: any) { export interface AggConfigsOptions { typesRegistry: AggTypesRegistryStart; - fieldFormats: FieldFormatsStart; } export type CreateAggConfigParams = Assign; @@ -70,7 +68,6 @@ export type IAggConfigs = AggConfigs; export class AggConfigs { public indexPattern: IndexPattern; public timeRange?: TimeRange; - private readonly fieldFormats: FieldFormatsStart; private readonly typesRegistry: AggTypesRegistryStart; aggs: IAggConfig[]; @@ -86,7 +83,6 @@ export class AggConfigs { this.aggs = []; this.indexPattern = indexPattern; - this.fieldFormats = opts.fieldFormats; configStates.forEach((params: any) => this.createAggConfig(params)); } @@ -117,7 +113,6 @@ export class AggConfigs { const aggConfigs = new AggConfigs(this.indexPattern, this.aggs.filter(filterAggs), { typesRegistry: this.typesRegistry, - fieldFormats: this.fieldFormats, }); return aggConfigs; @@ -134,14 +129,10 @@ export class AggConfigs { aggConfig = params; params.parent = this; } else { - aggConfig = new AggConfig( - this, - { - ...params, - type: typeof type === 'string' ? this.typesRegistry.get(type) : type, - }, - { fieldFormats: this.fieldFormats } - ); + aggConfig = new AggConfig(this, { + ...params, + type: typeof type === 'string' ? this.typesRegistry.get(type) : type, + }); } if (addToAggConfigs) { diff --git a/src/plugins/data/public/search/aggs/agg_type.test.ts b/src/plugins/data/public/search/aggs/agg_type.test.ts index cc45b935d45b54..99b1c4d8612192 100644 --- a/src/plugins/data/public/search/aggs/agg_type.test.ts +++ b/src/plugins/data/public/search/aggs/agg_type.test.ts @@ -159,47 +159,6 @@ describe('AggType Class', () => { }); }); - describe('getFormat', function () { - let aggConfig: IAggConfig; - let field: any; - - beforeEach(() => { - aggConfig = ({ - getField: jest.fn(() => field), - } as unknown) as IAggConfig; - }); - - test('returns the formatter for the aggConfig', () => { - const aggType = new AggType( - { - name: 'name', - title: 'title', - }, - dependencies - ); - - field = { - format: 'format', - }; - - expect(aggType.getFormat(aggConfig)).toBe('format'); - }); - - test('returns default formatter', () => { - const aggType = new AggType( - { - name: 'name', - title: 'title', - }, - dependencies - ); - - field = undefined; - - expect(aggType.getFormat(aggConfig)).toBe('default'); - }); - }); - describe('getSerializedFormat', () => { test('returns the default serialized field format if it exists', () => { const aggConfig = ({ diff --git a/src/plugins/data/public/search/aggs/agg_type.ts b/src/plugins/data/public/search/aggs/agg_type.ts index e909cd8134e83f..13655afdf469ea 100644 --- a/src/plugins/data/public/search/aggs/agg_type.ts +++ b/src/plugins/data/public/search/aggs/agg_type.ts @@ -28,7 +28,6 @@ import { IAggConfigs } from './agg_configs'; import { Adapters } from '../../../../../plugins/inspector/public'; import { BaseParamType } from './param_types/base'; import { AggParamType } from './param_types/agg'; -import { KBN_FIELD_TYPES, IFieldFormat } from '../../../common'; import { ISearchSource } from '../search_source'; import { GetInternalStartServicesFn } from '../../types'; @@ -58,7 +57,6 @@ export interface AggTypeConfig< inspectorAdapters: Adapters, abortSignal?: AbortSignal ) => Promise; - getFormat?: (agg: TAggConfig) => IFieldFormat; getSerializedFormat?: (agg: TAggConfig) => SerializedFieldFormat; getValue?: (agg: TAggConfig, bucket: any) => any; getKey?: (bucket: any, key: any, agg: TAggConfig) => any; @@ -197,16 +195,6 @@ export class AggType< inspectorAdapters: Adapters, abortSignal?: AbortSignal ) => Promise; - /** - * Pick a format for the values produced by this agg type, - * overridden by several metrics that always output a simple - * number - * - * @param {agg} agg - the agg to pick a format for - * @return {FieldFormat} - */ - getFormat: (agg: TAggConfig) => IFieldFormat; - /** * Get the serialized format for the values produced by this agg type, * overridden by several metrics that always output a simple number. @@ -283,15 +271,6 @@ export class AggType< this.decorateAggConfig = config.decorateAggConfig || (() => ({})); this.postFlightRequest = config.postFlightRequest || identity; - this.getFormat = - config.getFormat || - ((agg: TAggConfig) => { - const field = agg.getField(); - const { fieldFormats } = getInternalStartServices(); - - return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); - }); - this.getSerializedFormat = config.getSerializedFormat || ((agg: TAggConfig) => { diff --git a/src/plugins/data/public/search/aggs/agg_types.ts b/src/plugins/data/public/search/aggs/agg_types.ts index 2af29d36002460..68542b66e6c358 100644 --- a/src/plugins/data/public/search/aggs/agg_types.ts +++ b/src/plugins/data/public/search/aggs/agg_types.ts @@ -18,7 +18,8 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { QuerySetup } from '../../query/query_service'; +import { TimeRange, TimeRangeBounds } from '../../../common'; +import { GetInternalStartServicesFn } from '../../types'; import { getCountMetricAgg } from './metrics/count'; import { getAvgMetricAgg } from './metrics/avg'; @@ -54,18 +55,16 @@ import { getBucketAvgMetricAgg } from './metrics/bucket_avg'; import { getBucketMinMetricAgg } from './metrics/bucket_min'; import { getBucketMaxMetricAgg } from './metrics/bucket_max'; -import { GetInternalStartServicesFn } from '../../types'; - export interface AggTypesDependencies { - uiSettings: IUiSettingsClient; - query: QuerySetup; + calculateBounds: (timeRange: TimeRange) => TimeRangeBounds; getInternalStartServices: GetInternalStartServicesFn; + uiSettings: IUiSettingsClient; } export const getAggTypes = ({ - uiSettings, - query, + calculateBounds, getInternalStartServices, + uiSettings, }: AggTypesDependencies) => ({ metrics: [ getCountMetricAgg({ getInternalStartServices }), @@ -91,7 +90,7 @@ export const getAggTypes = ({ getGeoCentroidMetricAgg({ getInternalStartServices }), ], buckets: [ - getDateHistogramBucketAgg({ uiSettings, query, getInternalStartServices }), + getDateHistogramBucketAgg({ calculateBounds, uiSettings, getInternalStartServices }), getHistogramBucketAgg({ uiSettings, getInternalStartServices }), getRangeBucketAgg({ getInternalStartServices }), getDateRangeBucketAgg({ uiSettings, getInternalStartServices }), diff --git a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts index 44d99375bbd302..8e862b5692ca39 100644 --- a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts @@ -26,7 +26,6 @@ import { AggConfigs, CreateAggConfigParams } from '../agg_configs'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './bucket_agg_type'; import { mockAggTypesRegistry } from '../test_helpers'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; const indexPattern = { id: '1234', @@ -220,10 +219,9 @@ const nestedOtherResponse = { describe('Terms Agg Other bucket helper', () => { const typesRegistry = mockAggTypesRegistry(); - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const getAggConfigs = (aggs: CreateAggConfigParams[] = []) => { - return new AggConfigs(indexPattern, [...aggs], { typesRegistry, fieldFormats }); + return new AggConfigs(indexPattern, [...aggs], { typesRegistry }); }; describe('buildOtherBucketAgg', () => { diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts index 2f03b8ec671123..518bdbfe0c1352 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts @@ -30,7 +30,6 @@ import { import { BUCKET_TYPES } from '../bucket_agg_types'; import { RangeFilter } from '../../../../../common'; import { coreMock, notificationServiceMock } from '../../../../../../../core/public/mocks'; -import { queryServiceMock } from '../../../../query/mocks'; import { fieldFormatsServiceMock } from '../../../../field_formats/mocks'; import { InternalStartServices } from '../../../../types'; @@ -46,13 +45,13 @@ describe('AggConfig Filters', () => { const { uiSettings } = coreMock.createSetup(); aggTypesDependencies = { - uiSettings, - query: queryServiceMock.createSetupContract(), + calculateBounds: jest.fn(), getInternalStartServices: () => (({ fieldFormats: fieldFormatsServiceMock.createStartContract(), notifications: notificationServiceMock.createStartContract(), } as unknown) as InternalStartServices), + uiSettings, }; mockDataServices(); @@ -82,7 +81,6 @@ describe('AggConfig Filters', () => { ], { typesRegistry: mockAggTypesRegistry([getDateHistogramBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); const bucketKey = 1422579600000; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts index 0d66d9cfcdca2c..08f39e10b6006f 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts @@ -76,7 +76,6 @@ describe('AggConfig Filters', () => { ], { typesRegistry: mockAggTypesRegistry([getDateRangeBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts index 0fdb07cc4198a5..c5ad1a61e6676f 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts @@ -73,7 +73,6 @@ describe('AggConfig Filters', () => { ], { typesRegistry: mockAggTypesRegistry([getFiltersBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts index 396d515f3b5809..3f9f5dd5672f0a 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts @@ -23,12 +23,21 @@ import { mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../bucket_agg_type'; import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common'; +import { GetInternalStartServicesFn, InternalStartServices } from '../../../../types'; +import { FieldFormatsStart } from '../../../../field_formats'; import { fieldFormatsServiceMock } from '../../../../field_formats/mocks'; describe('AggConfig Filters', () => { + let getInternalStartServices: GetInternalStartServicesFn; + let fieldFormats: FieldFormatsStart; + + beforeEach(() => { + fieldFormats = fieldFormatsServiceMock.createStartContract(); + getInternalStartServices = () => (({ fieldFormats } as unknown) as InternalStartServices); + }); + describe('histogram', () => { const getConfig = (() => {}) as FieldFormatsGetConfigFn; - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const getAggConfigs = () => { const field = { name: 'bytes', @@ -57,21 +66,25 @@ describe('AggConfig Filters', () => { }, }, ], - { typesRegistry: mockAggTypesRegistry(), fieldFormats } + { typesRegistry: mockAggTypesRegistry() } ); }; test('should return an range filter for histogram', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterHistogram(aggConfigs.aggs[0] as IBucketAggConfig, '2048'); + const filter = createFilterHistogram(getInternalStartServices)( + aggConfigs.aggs[0] as IBucketAggConfig, + '2048' + ); + expect(fieldFormats.deserialize).toHaveBeenCalledTimes(1); expect(filter).toHaveProperty('meta'); expect(filter.meta).toHaveProperty('index', '1234'); expect(filter).toHaveProperty('range'); expect(filter.range).toHaveProperty('bytes'); expect(filter.range.bytes).toHaveProperty('gte', 2048); expect(filter.range.bytes).toHaveProperty('lt', 3072); - expect(filter.meta).toHaveProperty('formattedValue', '2,048'); + expect(filter.meta).toHaveProperty('formattedValue'); }); }); }); diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts index f8e7747d49147c..f3626bc9130ad3 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts @@ -19,15 +19,20 @@ import { IBucketAggConfig } from '../bucket_agg_type'; import { buildRangeFilter, RangeFilterParams } from '../../../../../common'; +import { GetInternalStartServicesFn } from '../../../../types'; -export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { - const value = parseInt(key, 10); - const params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval }; +/** @internal */ +export const createFilterHistogram = (getInternalStartServices: GetInternalStartServicesFn) => { + return (aggConfig: IBucketAggConfig, key: string) => { + const { fieldFormats } = getInternalStartServices(); + const value = parseInt(key, 10); + const params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval }; - return buildRangeFilter( - aggConfig.params.field, - params, - aggConfig.getIndexPattern(), - aggConfig.fieldFormatter()(key) - ); + return buildRangeFilter( + aggConfig.params.field, + params, + aggConfig.getIndexPattern(), + fieldFormats.deserialize(aggConfig.toSerializedFieldFormat()).convert(key) + ); + }; }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts index 990adde5f8a0bd..89a5fd65778912 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts @@ -55,7 +55,7 @@ describe('AggConfig Filters', () => { }, } as any; - return new AggConfigs(indexPattern, aggs, { typesRegistry, fieldFormats }); + return new AggConfigs(indexPattern, aggs, { typesRegistry }); }; test('should return a range filter for ip_range agg', () => { diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts index 564e7b4763c8d5..238e5737d8f474 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts @@ -24,19 +24,29 @@ import { AggConfigs } from '../../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../bucket_agg_type'; +import { FieldFormatsStart } from '../../../../field_formats'; import { fieldFormatsServiceMock } from '../../../../field_formats/mocks'; import { notificationServiceMock } from '../../../../../../../core/public/mocks'; -import { InternalStartServices } from '../../../../types'; +import { GetInternalStartServicesFn, InternalStartServices } from '../../../../types'; describe('AggConfig Filters', () => { describe('range', () => { let aggTypesDependencies: RangeBucketAggDependencies; + let getInternalStartServices: GetInternalStartServicesFn; + let fieldFormats: FieldFormatsStart; beforeEach(() => { + fieldFormats = fieldFormatsServiceMock.createStartContract(); + + getInternalStartServices = () => + (({ + fieldFormats, + notifications: notificationServiceMock.createStartContract(), + } as unknown) as InternalStartServices); + aggTypesDependencies = { getInternalStartServices: () => (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), notifications: notificationServiceMock.createStartContract(), } as unknown) as InternalStartServices), }; @@ -75,25 +85,28 @@ describe('AggConfig Filters', () => { ], { typesRegistry: mockAggTypesRegistry([getRangeBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; test('should return a range filter for range agg', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterRange(aggConfigs.aggs[0] as IBucketAggConfig, { - gte: 1024, - lt: 2048.0, - }); + const filter = createFilterRange(getInternalStartServices)( + aggConfigs.aggs[0] as IBucketAggConfig, + { + gte: 1024, + lt: 2048.0, + } + ); + expect(fieldFormats.deserialize).toHaveBeenCalledTimes(1); expect(filter).toHaveProperty('range'); expect(filter).toHaveProperty('meta'); expect(filter.meta).toHaveProperty('index', '1234'); expect(filter.range).toHaveProperty('bytes'); expect(filter.range.bytes).toHaveProperty('gte', 1024.0); expect(filter.range.bytes).toHaveProperty('lt', 2048.0); - expect(filter.meta).toHaveProperty('formattedValue', '≥ 1,024 and < 2,048'); + expect(filter.meta).toHaveProperty('formattedValue'); }); }); }); diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts index cbad8742bfab60..f9db2973af1369 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts @@ -19,12 +19,17 @@ import { IBucketAggConfig } from '../bucket_agg_type'; import { buildRangeFilter } from '../../../../../common'; +import { GetInternalStartServicesFn } from '../../../../types'; -export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { - return buildRangeFilter( - aggConfig.params.field, - params, - aggConfig.getIndexPattern(), - aggConfig.fieldFormatter()(params) - ); +/** @internal */ +export const createFilterRange = (getInternalStartServices: GetInternalStartServicesFn) => { + return (aggConfig: IBucketAggConfig, params: any) => { + const { fieldFormats } = getInternalStartServices(); + return buildRangeFilter( + aggConfig.params.field, + params, + aggConfig.getIndexPattern(), + fieldFormats.deserialize(aggConfig.toSerializedFieldFormat()).convert(params) + ); + }; }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts index 36e4bef025ef9b..a45087916a395c 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts @@ -60,7 +60,6 @@ describe('AggConfig Filters', () => { return new AggConfigs(indexPattern, aggs, { typesRegistry: mockAggTypesRegistry([getTermsBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, }); }; diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts index fc42d43b2fea81..e4c4bc0cedc3c4 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -27,28 +27,30 @@ import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterDateHistogram } from './create_filter/date_histogram'; import { intervalOptions } from './_interval_options'; -import { dateHistogramInterval, TimeRange } from '../../../../common'; import { writeParams } from '../agg_params'; import { isMetricAggType } from '../metrics/metric_agg_type'; -import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES, UI_SETTINGS } from '../../../../common'; -import { TimefilterContract } from '../../../query'; -import { QuerySetup } from '../../../query/query_service'; +import { + dateHistogramInterval, + KBN_FIELD_TYPES, + TimeRange, + TimeRangeBounds, + UI_SETTINGS, +} from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; import { BaseAggParams } from '../types'; import { ExtendedBounds } from './lib/extended_bounds'; -const detectedTimezone = moment.tz.guess(); -const tzOffset = moment().format('Z'); +type CalculateBoundsFn = (timeRange: TimeRange) => TimeRangeBounds; const updateTimeBuckets = ( agg: IBucketDateHistogramAggConfig, - timefilter: TimefilterContract, + calculateBounds: CalculateBoundsFn, customBuckets?: IBucketDateHistogramAggConfig['buckets'] ) => { const bounds = agg.params.timeRange && (agg.fieldIsTimeField() || agg.params.interval === 'auto') - ? timefilter.calculateBounds(agg.params.timeRange) + ? calculateBounds(agg.params.timeRange) : undefined; const buckets = customBuckets || agg.buckets; buckets.setBounds(bounds); @@ -56,9 +58,9 @@ const updateTimeBuckets = ( }; export interface DateHistogramBucketAggDependencies { - uiSettings: IUiSettingsClient; - query: QuerySetup; + calculateBounds: CalculateBoundsFn; getInternalStartServices: GetInternalStartServicesFn; + uiSettings: IUiSettingsClient; } export interface IBucketDateHistogramAggConfig extends IBucketAggConfig { @@ -83,9 +85,9 @@ export interface AggParamsDateHistogram extends BaseAggParams { } export const getDateHistogramBucketAgg = ({ - uiSettings, - query, + calculateBounds, getInternalStartServices, + uiSettings, }: DateHistogramBucketAggDependencies) => new BucketAggType( { @@ -123,35 +125,19 @@ export const getDateHistogramBucketAgg = ({ get() { if (buckets) return buckets; - const { timefilter } = query.timefilter; buckets = new TimeBuckets({ 'histogram:maxBars': uiSettings.get(UI_SETTINGS.HISTOGRAM_MAX_BARS), 'histogram:barTarget': uiSettings.get(UI_SETTINGS.HISTOGRAM_BAR_TARGET), dateFormat: uiSettings.get('dateFormat'), 'dateFormat:scaled': uiSettings.get('dateFormat:scaled'), }); - updateTimeBuckets(this, timefilter, buckets); + updateTimeBuckets(this, calculateBounds, buckets); return buckets; }, } as any, }; }, - getFormat(agg) { - const { fieldFormats } = getInternalStartServices(); - const DateFieldFormat = fieldFormats.getType(FIELD_FORMAT_IDS.DATE); - - if (!DateFieldFormat) { - throw new Error('Unable to retrieve Date Field Format'); - } - - return new DateFieldFormat( - { - pattern: agg.buckets.getScaledDateFormat(), - }, - (key: string) => uiSettings.get(key) - ); - }, getSerializedFormat(agg) { return { id: 'date', @@ -210,8 +196,7 @@ export const getDateHistogramBucketAgg = ({ default: 'auto', options: intervalOptions, write(agg, output, aggs) { - const { timefilter } = query.timefilter; - updateTimeBuckets(agg, timefilter); + updateTimeBuckets(agg, calculateBounds); const { useNormalizedEsInterval, scaleMetricValues } = agg.params; const interval = agg.buckets.getInterval(useNormalizedEsInterval); @@ -272,6 +257,8 @@ export const getDateHistogramBucketAgg = ({ if (!tz) { // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz'); + const detectedTimezone = moment.tz.guess(); + const tzOffset = moment().format('Z'); tz = isDefaultTimezone ? detectedTimezone || tzOffset : uiSettings.get('dateFormat:tz'); diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.test.ts b/src/plugins/data/public/search/aggs/buckets/date_range.test.ts index e1881c3bbc7f4c..0829d6e9cdc9f7 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_range.test.ts @@ -78,7 +78,6 @@ describe('date_range params', () => { ], { typesRegistry: mockAggTypesRegistry([getDateRangeBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.ts b/src/plugins/data/public/search/aggs/buckets/date_range.ts index 3e14ab422ccbee..dbcf5517fb08fd 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_range.ts @@ -25,9 +25,9 @@ import { IUiSettingsClient } from 'src/core/public'; import { BUCKET_TYPES } from './bucket_agg_types'; import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; -import { convertDateRangeToString, DateRangeKey } from './lib/date_range'; +import { DateRangeKey } from './lib/date_range'; -import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; import { BaseAggParams } from '../types'; @@ -58,18 +58,6 @@ export const getDateRangeBucketAgg = ({ getKey({ from, to }): DateRangeKey { return { from, to }; }, - getFormat(agg) { - const { fieldFormats } = getInternalStartServices(); - - const formatter = agg.fieldOwnFormatter( - TEXT_CONTEXT_TYPE, - fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE) - ); - const DateRangeFormat = FieldFormat.from(function (range: DateRangeKey) { - return convertDateRangeToString(range, formatter); - }); - return new DateRangeFormat(); - }, getSerializedFormat(agg) { return { id: 'date_range', diff --git a/src/plugins/data/public/search/aggs/buckets/filter.ts b/src/plugins/data/public/search/aggs/buckets/filter.ts index 69157edad4f680..d048df9f0e43e8 100644 --- a/src/plugins/data/public/search/aggs/buckets/filter.ts +++ b/src/plugins/data/public/search/aggs/buckets/filter.ts @@ -41,6 +41,7 @@ export const getFilterBucketAgg = ({ getInternalStartServices }: FilterBucketAgg { name: BUCKET_TYPES.FILTER, title: filterTitle, + makeLabel: () => filterTitle, params: [ { name: 'geo_bounding_box', diff --git a/src/plugins/data/public/search/aggs/buckets/filters.test.ts b/src/plugins/data/public/search/aggs/buckets/filters.test.ts index 295e740a2a7809..7554e4081726cc 100644 --- a/src/plugins/data/public/search/aggs/buckets/filters.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/filters.test.ts @@ -71,7 +71,6 @@ describe('Filters Agg', () => { ], { typesRegistry: mockAggTypesRegistry([getFiltersBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts index 877a817984dc6f..d4c0a5b3288445 100644 --- a/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts @@ -81,7 +81,6 @@ describe('Geohash Agg', () => { ], { typesRegistry: mockAggTypesRegistry(), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts index be339de5d7faea..fbe7c76681f816 100644 --- a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts +++ b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -54,6 +54,7 @@ export const getGeoHashBucketAgg = ({ getInternalStartServices }: GeoHashBucketA { name: BUCKET_TYPES.GEOHASH_GRID, title: geohashGridTitle, + makeLabel: () => geohashGridTitle, params: [ { name: 'field', diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/histogram.test.ts index 4756669f5b4b31..787603ee143613 100644 --- a/src/plugins/data/public/search/aggs/buckets/histogram.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/histogram.test.ts @@ -74,7 +74,6 @@ describe('Histogram Agg', () => { ], { typesRegistry: mockAggTypesRegistry([getHistogramBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.ts b/src/plugins/data/public/search/aggs/buckets/histogram.ts index c1fad17f488db2..ce275e2dc1639a 100644 --- a/src/plugins/data/public/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/histogram.ts @@ -67,7 +67,7 @@ export const getHistogramBucketAgg = ({ makeLabel(aggConfig) { return aggConfig.getFieldDisplayName(); }, - createFilter: createFilterHistogram, + createFilter: createFilterHistogram(getInternalStartServices), decorateAggConfig() { let autoBounds: AutoBounds; diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/ip_range.ts index b3e90bdf9b56a1..018fcb365b5850 100644 --- a/src/plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/ip_range.ts @@ -23,13 +23,8 @@ import { BucketAggType } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterIpRange } from './create_filter/ip_range'; -import { - convertIPRangeToString, - IpRangeKey, - RangeIpRangeAggKey, - CidrMaskIpRangeAggKey, -} from './lib/ip_range'; -import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common'; +import { IpRangeKey, RangeIpRangeAggKey, CidrMaskIpRangeAggKey } from './lib/ip_range'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; import { BaseAggParams } from '../types'; @@ -67,17 +62,6 @@ export const getIpRangeBucketAgg = ({ getInternalStartServices }: IpRangeBucketA } return { type: 'range', from: bucket.from, to: bucket.to }; }, - getFormat(agg) { - const { fieldFormats } = getInternalStartServices(); - const formatter = agg.fieldOwnFormatter( - TEXT_CONTEXT_TYPE, - fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.IP) - ); - const IpRangeFormat = FieldFormat.from(function (range: IpRangeKey) { - return convertIPRangeToString(range, formatter); - }); - return new IpRangeFormat(); - }, getSerializedFormat(agg) { return { id: 'ip_range', diff --git a/src/plugins/data/public/search/aggs/buckets/range.test.ts b/src/plugins/data/public/search/aggs/buckets/range.test.ts index 2b8a36f2fbdbcb..fea5572b75795c 100644 --- a/src/plugins/data/public/search/aggs/buckets/range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/range.test.ts @@ -22,30 +22,9 @@ import { AggConfigs } from '../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; import { FieldFormatsGetConfigFn, NumberFormat } from '../../../../common'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; import { notificationServiceMock } from '../../../../../../../src/core/public/mocks'; import { InternalStartServices } from '../../../types'; -const buckets = [ - { - to: 1024, - to_as_string: '1024.0', - doc_count: 20904, - }, - { - from: 1024, - from_as_string: '1024.0', - to: 2560, - to_as_string: '2560.0', - doc_count: 23358, - }, - { - from: 2560, - from_as_string: '2560.0', - doc_count: 174250, - }, -]; - describe('Range Agg', () => { let aggTypesDependencies: RangeBucketAggDependencies; @@ -53,7 +32,6 @@ describe('Range Agg', () => { aggTypesDependencies = { getInternalStartServices: () => (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), notifications: notificationServiceMock.createStartContract(), } as unknown) as InternalStartServices), }; @@ -99,23 +77,10 @@ describe('Range Agg', () => { ], { typesRegistry: mockAggTypesRegistry([getRangeBucketAgg(aggTypesDependencies)]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; - describe('formatting', () => { - test('formats bucket keys properly', () => { - const aggConfigs = getAggConfigs(); - const agg = aggConfigs.aggs[0]; - const format = (val: any) => agg.fieldFormatter()(agg.getKey(val)); - - expect(format(buckets[0])).toBe('≥ -∞ and < 1 KB'); - expect(format(buckets[1])).toBe('≥ 1 KB and < 2.5 KB'); - expect(format(buckets[2])).toBe('≥ 2.5 KB and < +∞'); - }); - }); - describe('getSerializedFormat', () => { test('generates a serialized field format in the expected shape', () => { const aggConfigs = getAggConfigs(); diff --git a/src/plugins/data/public/search/aggs/buckets/range.ts b/src/plugins/data/public/search/aggs/buckets/range.ts index 543e5d66b9fa81..92c5193d55a209 100644 --- a/src/plugins/data/public/search/aggs/buckets/range.ts +++ b/src/plugins/data/public/search/aggs/buckets/range.ts @@ -19,16 +19,13 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './bucket_agg_type'; -import { FieldFormat, KBN_FIELD_TYPES } from '../../../../common'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { RangeKey } from './range_key'; import { createFilterRange } from './create_filter/range'; import { BUCKET_TYPES } from './bucket_agg_types'; import { GetInternalStartServicesFn } from '../../../types'; import { BaseAggParams } from '../types'; -const keyCaches = new WeakMap(); -const formats = new WeakMap(); - const rangeTitle = i18n.translate('data.search.aggs.buckets.rangeTitle', { defaultMessage: 'Range', }); @@ -45,12 +42,14 @@ export interface AggParamsRange extends BaseAggParams { }>; } -export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDependencies) => - new BucketAggType( +export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDependencies) => { + const keyCaches = new WeakMap(); + + return new BucketAggType( { name: BUCKET_TYPES.RANGE, title: rangeTitle, - createFilter: createFilterRange, + createFilter: createFilterRange(getInternalStartServices), makeLabel(aggConfig) { return i18n.translate('data.search.aggs.aggTypesLabel', { defaultMessage: '{fieldName} ranges', @@ -77,30 +76,6 @@ export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDe return key; }, - getFormat(agg) { - let aggFormat = formats.get(agg); - if (aggFormat) return aggFormat; - - const RangeFormat = FieldFormat.from((range: any) => { - const format = agg.fieldOwnFormatter(); - const gte = '\u2265'; - const lt = '\u003c'; - return i18n.translate('data.search.aggs.aggTypes.rangesFormatMessage', { - defaultMessage: '{gte} {from} and {lt} {to}', - values: { - gte, - from: format(range.gte), - lt, - to: format(range.lt), - }, - }); - }); - - aggFormat = new RangeFormat(); - - formats.set(agg, aggFormat); - return aggFormat; - }, getSerializedFormat(agg) { const format = agg.params.field ? agg.params.field.format.toJSON() : {}; return { @@ -132,3 +107,4 @@ export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDe }, { getInternalStartServices } ); +}; diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts index 156f7f8108482c..8fe833aa99cb2e 100644 --- a/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts @@ -72,7 +72,6 @@ describe('Significant Terms Agg', () => { typesRegistry: mockAggTypesRegistry([ getSignificantTermsBucketAgg(aggTypesDependencies), ]), - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/terms.test.ts index 9769efb6da7494..2c5be00c8afea5 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms.test.ts @@ -20,11 +20,9 @@ import { AggConfigs } from '../agg_configs'; import { mockAggTypesRegistry } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; describe('Terms Agg', () => { describe('order agg editor UI', () => { - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const getAggConfigs = (params: Record = {}) => { const indexPattern = { id: '1234', @@ -49,7 +47,7 @@ describe('Terms Agg', () => { type: BUCKET_TYPES.TERMS, }, ], - { typesRegistry: mockAggTypesRegistry(), fieldFormats } + { typesRegistry: mockAggTypesRegistry() } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/terms.ts b/src/plugins/data/public/search/aggs/buckets/terms.ts index 1e8e9ab4ef9d09..57a5ebf72316c6 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms.ts @@ -30,7 +30,7 @@ import { AggConfigSerialized, BaseAggParams, IAggConfigs } from '../types'; import { Adapters } from '../../../../../inspector/public'; import { ISearchSource } from '../../search_source'; -import { IFieldFormat, FieldFormatsContentType, KBN_FIELD_TYPES } from '../../../../common'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { getRequestInspectorStats, getResponseInspectorStats } from '../../expressions'; import { @@ -88,22 +88,6 @@ export const getTermsBucketAgg = ({ getInternalStartServices }: TermsBucketAggDe const params = agg.params; return agg.getFieldDisplayName() + ': ' + params.order.text; }, - getFormat(bucket): IFieldFormat { - return { - getConverterFor: (type: FieldFormatsContentType) => { - return (val: any) => { - if (val === '__other__') { - return bucket.params.otherBucketLabel; - } - if (val === '__missing__') { - return bucket.params.missingBucketLabel; - } - - return bucket.params.field.format.convert(val, type); - }; - }, - } as IFieldFormat; - }, getSerializedFormat(agg) { const format = agg.params.field ? agg.params.field.format.toJSON() : {}; return { diff --git a/src/plugins/data/public/search/aggs/index.test.ts b/src/plugins/data/public/search/aggs/index.test.ts index 4864a8b9d013bb..73068326ca97ee 100644 --- a/src/plugins/data/public/search/aggs/index.test.ts +++ b/src/plugins/data/public/search/aggs/index.test.ts @@ -22,7 +22,6 @@ import { getAggTypes } from './index'; import { isBucketAggType } from './buckets/bucket_agg_type'; import { isMetricAggType } from './metrics/metric_agg_type'; -import { QueryStart } from '../../query'; import { FieldFormatsStart } from '../../field_formats'; import { InternalStartServices } from '../../types'; @@ -31,13 +30,13 @@ describe('AggTypesComponent', () => { const coreStart = coreMock.createSetup(); const aggTypes = getAggTypes({ - uiSettings: coreSetup.uiSettings, - query: {} as QueryStart, + calculateBounds: jest.fn(), getInternalStartServices: () => (({ notifications: coreStart.notifications, fieldFormats: {} as FieldFormatsStart, } as unknown) as InternalStartServices), + uiSettings: coreSetup.uiSettings, }); const { buckets, metrics } = aggTypes; diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts b/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts index 38312ec5cfa81c..a30e426dd23901 100644 --- a/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts +++ b/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts @@ -46,7 +46,7 @@ const averageBucketTitle = i18n.translate('data.search.aggs.metrics.averageBucke export const getBucketAvgMetricAgg = ({ getInternalStartServices, }: BucketAvgMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = siblingPipelineAggHelper; + const { subtype, params, getSerializedFormat } = siblingPipelineAggHelper; return new MetricAggType( { @@ -55,7 +55,6 @@ export const getBucketAvgMetricAgg = ({ makeLabel: (agg) => makeNestedLabel(agg, overallAverageLabel), subtype, params: [...params()], - getFormat, getSerializedFormat, getValue(agg, bucket) { const customMetric = agg.getParam('customMetric'); diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_max.ts b/src/plugins/data/public/search/aggs/metrics/bucket_max.ts index e2c6a5105bac66..307c7ed3f9d386 100644 --- a/src/plugins/data/public/search/aggs/metrics/bucket_max.ts +++ b/src/plugins/data/public/search/aggs/metrics/bucket_max.ts @@ -45,7 +45,7 @@ const maxBucketTitle = i18n.translate('data.search.aggs.metrics.maxBucketTitle', export const getBucketMaxMetricAgg = ({ getInternalStartServices, }: BucketMaxMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = siblingPipelineAggHelper; + const { subtype, params, getSerializedFormat } = siblingPipelineAggHelper; return new MetricAggType( { @@ -54,7 +54,6 @@ export const getBucketMaxMetricAgg = ({ makeLabel: (agg) => makeNestedLabel(agg, overallMaxLabel), subtype, params: [...params()], - getFormat, getSerializedFormat, }, { diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_min.ts b/src/plugins/data/public/search/aggs/metrics/bucket_min.ts index c46a3eb9425d1f..bb4ed9d44b0b33 100644 --- a/src/plugins/data/public/search/aggs/metrics/bucket_min.ts +++ b/src/plugins/data/public/search/aggs/metrics/bucket_min.ts @@ -45,7 +45,7 @@ const minBucketTitle = i18n.translate('data.search.aggs.metrics.minBucketTitle', export const getBucketMinMetricAgg = ({ getInternalStartServices, }: BucketMinMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = siblingPipelineAggHelper; + const { subtype, params, getSerializedFormat } = siblingPipelineAggHelper; return new MetricAggType( { @@ -54,7 +54,6 @@ export const getBucketMinMetricAgg = ({ makeLabel: (agg) => makeNestedLabel(agg, overallMinLabel), subtype, params: [...params()], - getFormat, getSerializedFormat, }, { diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts b/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts index 57212ec9ff91b2..dd065b52acd129 100644 --- a/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts +++ b/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts @@ -45,7 +45,7 @@ const sumBucketTitle = i18n.translate('data.search.aggs.metrics.sumBucketTitle', export const getBucketSumMetricAgg = ({ getInternalStartServices, }: BucketSumMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = siblingPipelineAggHelper; + const { subtype, params, getSerializedFormat } = siblingPipelineAggHelper; return new MetricAggType( { @@ -54,7 +54,6 @@ export const getBucketSumMetricAgg = ({ makeLabel: (agg) => makeNestedLabel(agg, overallSumLabel), subtype, params: [...params()], - getFormat, getSerializedFormat, }, { diff --git a/src/plugins/data/public/search/aggs/metrics/cardinality.ts b/src/plugins/data/public/search/aggs/metrics/cardinality.ts index 2855cc1b6b16eb..efc79a85595661 100644 --- a/src/plugins/data/public/search/aggs/metrics/cardinality.ts +++ b/src/plugins/data/public/search/aggs/metrics/cardinality.ts @@ -49,11 +49,6 @@ export const getCardinalityMetricAgg = ({ values: { field: aggConfig.getFieldDisplayName() }, }); }, - getFormat() { - const { fieldFormats } = getInternalStartServices(); - - return fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - }, getSerializedFormat(agg) { return { id: 'number', diff --git a/src/plugins/data/public/search/aggs/metrics/count.ts b/src/plugins/data/public/search/aggs/metrics/count.ts index 4c7b8139b01628..86faca053a9cf7 100644 --- a/src/plugins/data/public/search/aggs/metrics/count.ts +++ b/src/plugins/data/public/search/aggs/metrics/count.ts @@ -20,7 +20,6 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; export interface CountMetricAggDependencies { @@ -40,11 +39,6 @@ export const getCountMetricAgg = ({ getInternalStartServices }: CountMetricAggDe defaultMessage: 'Count', }); }, - getFormat() { - const { fieldFormats } = getInternalStartServices(); - - return fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - }, getSerializedFormat(agg) { return { id: 'number', diff --git a/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts b/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts index c392f44a7961ed..3de88bb71740f1 100644 --- a/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts +++ b/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts @@ -46,7 +46,7 @@ const cumulativeSumTitle = i18n.translate('data.search.aggs.metrics.cumulativeSu export const getCumulativeSumMetricAgg = ({ getInternalStartServices, }: CumulativeSumMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = parentPipelineAggHelper; + const { subtype, params, getSerializedFormat } = parentPipelineAggHelper; return new MetricAggType( { @@ -55,7 +55,6 @@ export const getCumulativeSumMetricAgg = ({ makeLabel: (agg) => makeNestedLabel(agg, cumulativeSumLabel), subtype, params: [...params()], - getFormat, getSerializedFormat, }, { diff --git a/src/plugins/data/public/search/aggs/metrics/derivative.ts b/src/plugins/data/public/search/aggs/metrics/derivative.ts index f3c1cc9bc29773..c9507029080e61 100644 --- a/src/plugins/data/public/search/aggs/metrics/derivative.ts +++ b/src/plugins/data/public/search/aggs/metrics/derivative.ts @@ -46,7 +46,7 @@ const derivativeTitle = i18n.translate('data.search.aggs.metrics.derivativeTitle export const getDerivativeMetricAgg = ({ getInternalStartServices, }: DerivativeMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = parentPipelineAggHelper; + const { subtype, params, getSerializedFormat } = parentPipelineAggHelper; return new MetricAggType( { @@ -57,7 +57,6 @@ export const getDerivativeMetricAgg = ({ }, subtype, params: [...params()], - getFormat, getSerializedFormat, }, { diff --git a/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts b/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts index 2a74a446ce84e0..73acd268600763 100644 --- a/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts @@ -18,14 +18,12 @@ */ import { i18n } from '@kbn/i18n'; -import { noop, identity } from 'lodash'; +import { noop } from 'lodash'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; -import { FieldFormat } from '../../../../../common'; - const metricAggFilter = [ '!top_hits', '!percentiles', @@ -73,18 +71,6 @@ export const parentPipelineAggHelper = { ] as Array>; }, - getFormat(agg: IMetricAggConfig) { - let subAgg; - const customMetric = agg.getParam('customMetric'); - - if (customMetric) { - subAgg = customMetric; - } else { - subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); - } - return subAgg ? subAgg.type.getFormat(subAgg) : new (FieldFormat.from(identity))(); - }, - getSerializedFormat(agg: IMetricAggConfig) { let subAgg; const customMetric = agg.getParam('customMetric'); diff --git a/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts b/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts index 8e3e0143bf9154..347ac76b8e27b9 100644 --- a/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts @@ -17,12 +17,10 @@ * under the License. */ -import { identity } from 'lodash'; import { i18n } from '@kbn/i18n'; import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; -import { FieldFormat } from '../../../../../common'; const metricAggFilter: string[] = [ '!top_hits', @@ -87,13 +85,6 @@ export const siblingPipelineAggHelper = { ] as Array>; }, - getFormat(agg: IMetricAggConfig) { - const customMetric = agg.getParam('customMetric'); - return customMetric - ? customMetric.type.getFormat(customMetric) - : new (FieldFormat.from(identity))(); - }, - getSerializedFormat(agg: IMetricAggConfig) { const customMetric = agg.getParam('customMetric'); return customMetric ? customMetric.type.getSerializedFormat(customMetric) : {}; diff --git a/src/plugins/data/public/search/aggs/metrics/median.test.ts b/src/plugins/data/public/search/aggs/metrics/median.test.ts index 71c48f04a3ca8a..b3721e2c1e679b 100644 --- a/src/plugins/data/public/search/aggs/metrics/median.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/median.test.ts @@ -63,7 +63,6 @@ describe('AggTypeMetricMedianProvider class', () => { ], { typesRegistry, - fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, } ); }); diff --git a/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts index 83656db4ac5474..5c4ff91258fb00 100644 --- a/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts +++ b/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -22,7 +22,6 @@ import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; import { AggConfig } from '../agg_config'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../common'; import { FieldTypes } from '../param_types'; import { GetInternalStartServicesFn } from '../../../types'; @@ -82,14 +81,6 @@ export class MetricAggType { - const { fieldFormats } = dependencies.getInternalStartServices(); - const field = agg.getField(); - return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - }); - this.subtype = config.subtype || i18n.translate('data.search.aggs.metrics.metricAggregationsSubtypeTitle', { diff --git a/src/plugins/data/public/search/aggs/metrics/moving_avg.ts b/src/plugins/data/public/search/aggs/metrics/moving_avg.ts index abad2782f9d201..61384ef1dc1066 100644 --- a/src/plugins/data/public/search/aggs/metrics/moving_avg.ts +++ b/src/plugins/data/public/search/aggs/metrics/moving_avg.ts @@ -48,7 +48,7 @@ const movingAvgLabel = i18n.translate('data.search.aggs.metrics.movingAvgLabel', export const getMovingAvgMetricAgg = ({ getInternalStartServices, }: MovingAvgMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = parentPipelineAggHelper; + const { subtype, params, getSerializedFormat } = parentPipelineAggHelper; return new MetricAggType( { @@ -57,7 +57,6 @@ export const getMovingAvgMetricAgg = ({ title: movingAvgTitle, makeLabel: (agg) => makeNestedLabel(agg, movingAvgLabel), subtype, - getFormat, getSerializedFormat, params: [ ...params(), diff --git a/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts b/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts index 2201366cdf78b5..91149a3f29f94a 100644 --- a/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts @@ -24,14 +24,12 @@ import { getSerialDiffMetricAgg } from './serial_diff'; import { AggConfigs } from '../agg_configs'; import { mockAggTypesRegistry } from '../test_helpers'; import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; import { GetInternalStartServicesFn, InternalStartServices } from '../../../types'; import { notificationServiceMock } from '../../../../../../../src/core/public/mocks'; describe('parent pipeline aggs', function () { const getInternalStartServices: GetInternalStartServicesFn = () => (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), notifications: notificationServiceMock.createStartContract(), } as unknown) as InternalStartServices); @@ -76,9 +74,7 @@ describe('parent pipeline aggs', function () { const field = { name: 'field', format: { - type: { - id: 'bytes', - }, + toJSON: () => ({ id: 'bytes' }), }, }; const indexPattern = { @@ -111,7 +107,7 @@ describe('parent pipeline aggs', function () { schema: 'metric', }, ], - { typesRegistry, fieldFormats: getInternalStartServices().fieldFormats } + { typesRegistry } ); // Grab the aggConfig off the vis (we don't actually use the vis for anything else) @@ -197,14 +193,14 @@ describe('parent pipeline aggs', function () { ); }); - it('should have correct formatter', () => { + it('should have correct serialized format', () => { init({ metricAgg: '3', }); - expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); + expect(metricAgg.getSerializedFormat(aggConfig).id).toBe('bytes'); }); - it('should have correct customMetric nested formatter', () => { + it('should have correct customMetric nested serialized format', () => { init({ metricAgg: 'custom', customMetric: { @@ -222,7 +218,7 @@ describe('parent pipeline aggs', function () { schema: 'orderAgg', }, }); - expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); + expect(metricAgg.getSerializedFormat(aggConfig).id).toBe('bytes'); }); it("should call modifyAggConfigOnSearchRequestStart for its customMetric's parameters", () => { diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts index df52c10a82495b..39e371763ed4b1 100644 --- a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts @@ -74,7 +74,7 @@ describe('AggTypesMetricsPercentileRanksProvider class', function () { }, }, ], - { typesRegistry, fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats } + { typesRegistry } ); }); diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts index c5aee380b97762..1953c81a998740 100644 --- a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts +++ b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts @@ -22,7 +22,7 @@ import { MetricAggType } from './metric_agg_type'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; import { METRIC_TYPES } from './metric_agg_types'; -import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES } from '../../../../common'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; import { BaseAggParams } from '../types'; @@ -96,13 +96,6 @@ export const getPercentileRanksMetricAgg = ({ return values.map((value: any) => new ValueAggConfig(value)); }, - getFormat() { - const { fieldFormats } = getInternalStartServices(); - return ( - fieldFormats.getInstance(FIELD_FORMAT_IDS.PERCENT) || - fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER) - ); - }, getSerializedFormat(agg) { return { id: 'percent', diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts b/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts index 76382c01bcc108..52ab325ac5806b 100644 --- a/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts @@ -67,7 +67,7 @@ describe('AggTypesMetricsPercentilesProvider class', () => { }, }, ], - { typesRegistry, fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats } + { typesRegistry } ); }); diff --git a/src/plugins/data/public/search/aggs/metrics/serial_diff.ts b/src/plugins/data/public/search/aggs/metrics/serial_diff.ts index 7cb1b194fed1c1..9ea01be11fe8f8 100644 --- a/src/plugins/data/public/search/aggs/metrics/serial_diff.ts +++ b/src/plugins/data/public/search/aggs/metrics/serial_diff.ts @@ -46,7 +46,7 @@ const serialDiffLabel = i18n.translate('data.search.aggs.metrics.serialDiffLabel export const getSerialDiffMetricAgg = ({ getInternalStartServices, }: SerialDiffMetricAggDependencies) => { - const { subtype, params, getFormat, getSerializedFormat } = parentPipelineAggHelper; + const { subtype, params, getSerializedFormat } = parentPipelineAggHelper; return new MetricAggType( { @@ -55,7 +55,6 @@ export const getSerialDiffMetricAgg = ({ makeLabel: (agg) => makeNestedLabel(agg, serialDiffLabel), subtype, params: [...params()], - getFormat, getSerializedFormat, }, { diff --git a/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts b/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts index 56bd33b2b6345b..f08e850caadcec 100644 --- a/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts @@ -25,14 +25,12 @@ import { getBucketMaxMetricAgg } from './bucket_max'; import { AggConfigs } from '../agg_configs'; import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; import { mockAggTypesRegistry } from '../test_helpers'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; import { GetInternalStartServicesFn, InternalStartServices } from '../../../types'; import { notificationServiceMock } from '../../../../../../../src/core/public/mocks'; describe('sibling pipeline aggs', () => { const getInternalStartServices: GetInternalStartServicesFn = () => (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), notifications: notificationServiceMock.createStartContract(), } as unknown) as InternalStartServices); @@ -71,9 +69,7 @@ describe('sibling pipeline aggs', () => { const field = { name: 'field', format: { - type: { - id: 'bytes', - }, + toJSON: () => ({ id: 'bytes' }), }, }; const indexPattern = { @@ -112,7 +108,7 @@ describe('sibling pipeline aggs', () => { }, }, ], - { typesRegistry, fieldFormats: getInternalStartServices().fieldFormats } + { typesRegistry } ); // Grab the aggConfig off the vis (we don't actually use the vis for anything else) @@ -155,7 +151,7 @@ describe('sibling pipeline aggs', () => { expect(aggDsl.parentAggs['2-bucket'].aggs['2-metric'].avg.field).toEqual('field'); }); - it('should have correct formatter', () => { + it('should have correct serialized field format', () => { init({ customMetric: { id: '5', @@ -171,7 +167,7 @@ describe('sibling pipeline aggs', () => { }, }); - expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); + expect(metricAgg.getSerializedFormat(aggConfig).id).toBe('bytes'); }); it("should call modifyAggConfigOnSearchRequestStart for nested aggs' parameters", () => { diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts b/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts index 536764b2bcf0b8..2fa207e62771e3 100644 --- a/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts @@ -66,7 +66,7 @@ describe('AggTypeMetricStandardDeviationProvider class', () => { }, }, ], - { typesRegistry, fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats } + { typesRegistry } ); }; diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts b/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts index 49e0a3e4b349ab..94a970a72a46f5 100644 --- a/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts +++ b/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts @@ -91,7 +91,7 @@ describe('Top hit metric', () => { params, }, ], - { typesRegistry, fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats } + { typesRegistry } ); // Grab the aggConfig off the vis (we don't actually use the vis for anything else) diff --git a/src/plugins/data/public/search/aggs/mocks.ts b/src/plugins/data/public/search/aggs/mocks.ts index 16544fd8f46b08..7a5dcc9be45929 100644 --- a/src/plugins/data/public/search/aggs/mocks.ts +++ b/src/plugins/data/public/search/aggs/mocks.ts @@ -27,7 +27,6 @@ import { } from './'; import { SearchAggsSetup, SearchAggsStart } from './types'; import { mockAggTypesRegistry } from './test_helpers'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; const aggTypeBaseParamMock = () => ({ name: 'some_param', @@ -73,7 +72,6 @@ export const searchAggsStartMock = (): SearchAggsStart => ({ createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { typesRegistry: mockAggTypesRegistry(), - fieldFormats: fieldFormatsServiceMock.createStartContract(), }); }), types: mockAggTypesRegistry(), diff --git a/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts b/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts index 836aaad2cda0c3..385d0cd6c6b396 100644 --- a/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts +++ b/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts @@ -22,7 +22,6 @@ import { AggTypesRegistry, AggTypesRegistryStart } from '../agg_types_registry'; import { getAggTypes } from '../agg_types'; import { BucketAggType } from '../buckets/bucket_agg_type'; import { MetricAggType } from '../metrics/metric_agg_type'; -import { queryServiceMock } from '../../../query/mocks'; import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; import { InternalStartServices } from '../../../types'; import { TimeBucketsConfig } from '../buckets/lib/time_buckets/time_buckets'; @@ -79,8 +78,7 @@ export function mockAggTypesRegistry | MetricAggTyp coreSetup.uiSettings.get = mockUiSettings; const aggTypes = getAggTypes({ - uiSettings: coreSetup.uiSettings, - query: queryServiceMock.createSetupContract(), + calculateBounds: jest.fn(), getInternalStartServices: () => (({ fieldFormats: fieldFormatsServiceMock.createStartContract(), @@ -88,6 +86,7 @@ export function mockAggTypesRegistry | MetricAggTyp uiSettings: coreStart.uiSettings, injectedMetadata: coreStart.injectedMetadata, } as unknown) as InternalStartServices), + uiSettings: coreSetup.uiSettings, }); aggTypes.buckets.forEach((type) => registrySetup.registerBucket(type)); diff --git a/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts b/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts index 906b8862d00aab..c4846a98f124fd 100644 --- a/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts +++ b/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts @@ -19,6 +19,7 @@ import { set } from 'lodash'; import { FormattedData } from '../../../../../plugins/inspector/public'; +import { FormatFactory } from '../../../common/field_formats/utils'; import { TabbedTable } from '../tabify'; import { createFilter } from './create_filter'; @@ -38,14 +39,30 @@ import { createFilter } from './create_filter'; */ export async function buildTabularInspectorData( table: TabbedTable, - queryFilter: { addFilters: (filter: any) => void } + { + queryFilter, + deserializeFieldFormat, + }: { + queryFilter: { addFilters: (filter: any) => void }; + deserializeFieldFormat: FormatFactory; + } ) { const aggConfigs = table.columns.map((column) => column.aggConfig); const rows = table.rows.map((row) => { return table.columns.reduce>((prev, cur, colIndex) => { const value = row[cur.id]; - const fieldFormatter = cur.aggConfig.fieldFormatter('text'); - prev[`col-${colIndex}-${cur.aggConfig.id}`] = new FormattedData(value, fieldFormatter(value)); + + let format = cur.aggConfig.toSerializedFieldFormat(); + if (Object.keys(format).length < 1) { + // If no format exists, fall back to string as a default + format = { id: 'string' }; + } + const fieldFormatter = deserializeFieldFormat(format); + + prev[`col-${colIndex}-${cur.aggConfig.id}`] = new FormattedData( + value, + fieldFormatter.convert(value) + ); return prev; }, {}); }); diff --git a/src/plugins/data/public/search/expressions/create_filter.test.ts b/src/plugins/data/public/search/expressions/create_filter.test.ts index 51b5e175761bd7..23da060cba2032 100644 --- a/src/plugins/data/public/search/expressions/create_filter.test.ts +++ b/src/plugins/data/public/search/expressions/create_filter.test.ts @@ -22,12 +22,10 @@ import { AggConfigs, IAggConfig } from '../aggs'; import { TabbedTable } from '../tabify'; import { isRangeFilter, BytesFormat, FieldFormatsGetConfigFn } from '../../../common'; import { mockDataServices, mockAggTypesRegistry } from '../aggs/test_helpers'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; describe('createFilter', () => { let table: TabbedTable; let aggConfig: IAggConfig; - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const typesRegistry = mockAggTypesRegistry(); @@ -60,7 +58,7 @@ describe('createFilter', () => { params, }, ], - { typesRegistry, fieldFormats } + { typesRegistry } ); }; diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index 77475cd3ce88b9..e9daec0b4191b6 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -32,9 +32,22 @@ import { Adapters } from '../../../../../plugins/inspector/public'; import { IAggConfigs } from '../aggs'; import { ISearchSource } from '../search_source'; import { tabifyAggResponse } from '../tabify'; -import { Filter, Query, TimeRange, IIndexPattern, isRangeFilter } from '../../../common'; -import { FilterManager, calculateBounds, getTime } from '../../query'; -import { getSearchService, getQueryService, getIndexPatterns } from '../../services'; +import { + calculateBounds, + Filter, + getTime, + IIndexPattern, + isRangeFilter, + Query, + TimeRange, +} from '../../../common'; +import { FilterManager } from '../../query'; +import { + getFieldFormats, + getIndexPatterns, + getQueryService, + getSearchService, +} from '../../services'; import { buildTabularInspectorData } from './build_tabular_inspector_data'; import { getRequestInspectorStats, getResponseInspectorStats, serializeAggConfig } from './utils'; @@ -220,7 +233,11 @@ const handleCourierRequest = async ({ } inspectorAdapters.data.setTabularLoader( - () => buildTabularInspectorData((searchSource as any).tabifiedResponse, filterManager), + () => + buildTabularInspectorData((searchSource as any).tabifiedResponse, { + queryFilter: filterManager, + deserializeFieldFormat: getFieldFormats().deserialize, + }), { returnsFormattedValues: true } ); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index d5997c15817f69..134dc89c2421a0 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -25,10 +25,11 @@ import { ExpressionsSetup } from '../../../../plugins/expressions/public'; import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source'; import { TStrategyTypes } from './strategy_types'; import { getEsClient, LegacyApiCaller } from './legacy'; +import { getForceNow } from '../query/timefilter/lib/get_force_now'; +import { calculateBounds, TimeRange } from '../../common/query'; import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search'; import { esSearchStrategyProvider } from './es_search'; import { IndexPatternsContract } from '../index_patterns/index_patterns'; -import { QuerySetup } from '../query'; import { GetInternalStartServicesFn } from '../types'; import { SearchInterceptor } from './search_interceptor'; import { @@ -38,19 +39,16 @@ import { AggConfigs, getCalculateAutoTimeExpression, } from './aggs'; -import { FieldFormatsStart } from '../field_formats'; import { ISearchGeneric } from './i_search'; interface SearchServiceSetupDependencies { expressions: ExpressionsSetup; getInternalStartServices: GetInternalStartServicesFn; packageInfo: PackageInfo; - query: QuerySetup; } interface SearchServiceStartDependencies { indexPatterns: IndexPatternsContract; - fieldFormats: FieldFormatsStart; } /** @@ -85,9 +83,16 @@ export class SearchService implements Plugin { return strategy; }; + /** + * getForceNow uses window.location, so we must have a separate implementation + * of calculateBounds on the client and the server. + */ + private calculateBounds = (timeRange: TimeRange) => + calculateBounds(timeRange, { forceNow: getForceNow() }); + public setup( core: CoreSetup, - { expressions, packageInfo, query, getInternalStartServices }: SearchServiceSetupDependencies + { expressions, packageInfo, getInternalStartServices }: SearchServiceSetupDependencies ): ISearchSetup { this.esClient = getEsClient(core.injectedMetadata, core.http, packageInfo); @@ -100,9 +105,9 @@ export class SearchService implements Plugin { // register each agg type const aggTypes = getAggTypes({ - query, - uiSettings: core.uiSettings, + calculateBounds: this.calculateBounds, getInternalStartServices, + uiSettings: core.uiSettings, }); aggTypes.buckets.forEach((b) => aggTypesSetup.registerBucket(b)); aggTypes.metrics.forEach((m) => aggTypesSetup.registerMetric(m)); @@ -158,7 +163,6 @@ export class SearchService implements Plugin { calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), createAggConfigs: (indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { - fieldFormats: dependencies.fieldFormats, typesRegistry: aggTypesStart, }); }, diff --git a/src/plugins/data/public/search/tabify/get_columns.test.ts b/src/plugins/data/public/search/tabify/get_columns.test.ts index b4498aca4079cf..0c5551d95690f2 100644 --- a/src/plugins/data/public/search/tabify/get_columns.test.ts +++ b/src/plugins/data/public/search/tabify/get_columns.test.ts @@ -21,7 +21,6 @@ import { tabifyGetColumns } from './get_columns'; import { TabbedAggColumn } from './types'; import { AggConfigs } from '../aggs'; import { mockAggTypesRegistry, mockDataServices } from '../aggs/test_helpers'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; describe('get columns', () => { beforeEach(() => { @@ -29,7 +28,6 @@ describe('get columns', () => { }); const typesRegistry = mockAggTypesRegistry(); - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const createAggConfigs = (aggs: any[] = []) => { const field = { @@ -45,10 +43,7 @@ describe('get columns', () => { }, } as any; - return new AggConfigs(indexPattern, aggs, { - typesRegistry, - fieldFormats, - }); + return new AggConfigs(indexPattern, aggs, { typesRegistry }); }; test('should inject the metric after each bucket if the vis is hierarchical', () => { diff --git a/src/plugins/data/public/search/tabify/response_writer.test.ts b/src/plugins/data/public/search/tabify/response_writer.test.ts index 3334d858ce54e9..94473d23ccc398 100644 --- a/src/plugins/data/public/search/tabify/response_writer.test.ts +++ b/src/plugins/data/public/search/tabify/response_writer.test.ts @@ -21,7 +21,6 @@ import { TabbedAggResponseWriter } from './response_writer'; import { AggConfigs, BUCKET_TYPES } from '../aggs'; import { mockDataServices, mockAggTypesRegistry } from '../aggs/test_helpers'; import { TabbedResponseWriterOptions } from './types'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; describe('TabbedAggResponseWriter class', () => { beforeEach(() => { @@ -31,7 +30,6 @@ describe('TabbedAggResponseWriter class', () => { let responseWriter: TabbedAggResponseWriter; const typesRegistry = mockAggTypesRegistry(); - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const splitAggConfig = [ { @@ -73,17 +71,11 @@ describe('TabbedAggResponseWriter class', () => { }, } as any; - return new TabbedAggResponseWriter( - new AggConfigs(indexPattern, aggs, { - typesRegistry, - fieldFormats, - }), - { - metricsAtAllLevels: false, - partialRows: false, - ...opts, - } - ); + return new TabbedAggResponseWriter(new AggConfigs(indexPattern, aggs, { typesRegistry }), { + metricsAtAllLevels: false, + partialRows: false, + ...opts, + }); }; describe('Constructor', () => { diff --git a/src/plugins/data/public/search/tabify/tabify.test.ts b/src/plugins/data/public/search/tabify/tabify.test.ts index f6691360cec312..0a1e99c8bb2001 100644 --- a/src/plugins/data/public/search/tabify/tabify.test.ts +++ b/src/plugins/data/public/search/tabify/tabify.test.ts @@ -22,11 +22,9 @@ import { IndexPattern } from '../../index_patterns'; import { AggConfigs, IAggConfig, IAggConfigs } from '../aggs'; import { mockAggTypesRegistry } from '../aggs/test_helpers'; import { metricOnly, threeTermBuckets } from 'fixtures/fake_hierarchical_data'; -import { fieldFormatsServiceMock } from '../../field_formats/mocks'; describe('tabifyAggResponse Integration', () => { const typesRegistry = mockAggTypesRegistry(); - const fieldFormats = fieldFormatsServiceMock.createStartContract(); const createAggConfigs = (aggs: IAggConfig[] = []) => { const field = { @@ -42,10 +40,7 @@ describe('tabifyAggResponse Integration', () => { }, } as unknown) as IndexPattern; - return new AggConfigs(indexPattern, aggs, { - typesRegistry, - fieldFormats, - }); + return new AggConfigs(indexPattern, aggs, { typesRegistry }); }; const mockAggConfig = (agg: any): IAggConfig => (agg as unknown) as IAggConfig; diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 19d028c1d41e1b..6a4eb38b552ffb 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -202,6 +202,7 @@ export { castEsToKbnFieldTypeName, // query Filter, + getTime, Query, // timefilter RefreshInterval, diff --git a/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts b/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts index f563976cae9b82..ff9d67152e268d 100644 --- a/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts +++ b/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts @@ -17,7 +17,7 @@ * under the License. */ -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { getFieldCapabilities, resolveTimePattern, createNoMatchingIndicesError } from './lib'; @@ -37,9 +37,9 @@ interface FieldSubType { } export class IndexPatternsFetcher { - private _callDataCluster: APICaller; + private _callDataCluster: LegacyAPICaller; - constructor(callDataCluster: APICaller) { + constructor(callDataCluster: LegacyAPICaller) { this._callDataCluster = callDataCluster; } diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/es_api.ts b/src/plugins/data/server/index_patterns/fetcher/lib/es_api.ts index 734e845e857693..0738a16034d467 100644 --- a/src/plugins/data/server/index_patterns/fetcher/lib/es_api.ts +++ b/src/plugins/data/server/index_patterns/fetcher/lib/es_api.ts @@ -17,7 +17,7 @@ * under the License. */ -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { convertEsError } from './errors'; import { FieldCapsResponse } from './field_capabilities'; @@ -46,7 +46,7 @@ export interface IndexAliasResponse { * @return {Promise} */ export async function callIndexAliasApi( - callCluster: APICaller, + callCluster: LegacyAPICaller, indices: string[] | string ): Promise { try { @@ -71,7 +71,7 @@ export async function callIndexAliasApi( * @param {Array|String} indices * @return {Promise} */ -export async function callFieldCapsApi(callCluster: APICaller, indices: string[] | string) { +export async function callFieldCapsApi(callCluster: LegacyAPICaller, indices: string[] | string) { try { return (await callCluster('fieldCaps', { index: indices, diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_capabilities.ts b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_capabilities.ts index d8c94664322049..502364cdcba327 100644 --- a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_capabilities.ts +++ b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_capabilities.ts @@ -19,7 +19,7 @@ import { defaults, indexBy, sortBy } from 'lodash'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { callFieldCapsApi } from '../es_api'; import { FieldCapsResponse, readFieldCapsResponse } from './field_caps_response'; import { mergeOverrides } from './overrides'; @@ -39,7 +39,7 @@ export function concatIfUniq(arr: T[], value: T) { * @return {Promise>} */ export async function getFieldCapabilities( - callCluster: APICaller, + callCluster: LegacyAPICaller, indices: string | string[] = [], metaFields: string[] = [] ) { diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/resolve_time_pattern.ts b/src/plugins/data/server/index_patterns/fetcher/lib/resolve_time_pattern.ts index 764307bef0ba64..a01d34dbe9df6c 100644 --- a/src/plugins/data/server/index_patterns/fetcher/lib/resolve_time_pattern.ts +++ b/src/plugins/data/server/index_patterns/fetcher/lib/resolve_time_pattern.ts @@ -20,7 +20,7 @@ import { chain } from 'lodash'; import moment from 'moment'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { timePatternToWildcard } from './time_pattern_to_wildcard'; import { callIndexAliasApi, IndicesAliasResponse } from './es_api'; @@ -36,7 +36,7 @@ import { callIndexAliasApi, IndicesAliasResponse } from './es_api'; * and the indices that actually match the time * pattern (matches); */ -export async function resolveTimePattern(callCluster: APICaller, timePattern: string) { +export async function resolveTimePattern(callCluster: LegacyAPICaller, timePattern: string) { const aliases = await callIndexAliasApi(callCluster, timePatternToWildcard(timePattern)); const allIndexDetails = chain(aliases) diff --git a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts index 81e352fea51b26..35cee799ddb6aa 100644 --- a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts +++ b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts @@ -18,7 +18,7 @@ */ import { fetchProvider } from './fetch'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; jest.mock('../../../common', () => ({ DEFAULT_QUERY_LANGUAGE: 'lucene', @@ -28,7 +28,7 @@ jest.mock('../../../common', () => ({ })); let fetch: ReturnType; -let callCluster: APICaller; +let callCluster: LegacyAPICaller; function setupMockCallCluster( optCount: { optInCount?: number; optOutCount?: number } | null, @@ -78,7 +78,7 @@ function setupMockCallCluster( } throw new Error('invalid call'); - }) as unknown) as APICaller; + }) as unknown) as LegacyAPICaller; } describe('makeKQLUsageCollector', () => { diff --git a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts index 29f9be903a36f1..109d6f812334df 100644 --- a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts +++ b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts @@ -18,7 +18,7 @@ */ import { get } from 'lodash'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { DEFAULT_QUERY_LANGUAGE, UI_SETTINGS } from '../../../common'; const defaultSearchQueryLanguageSetting = DEFAULT_QUERY_LANGUAGE; @@ -30,7 +30,7 @@ export interface Usage { } export function fetchProvider(index: string) { - return async (callCluster: APICaller): Promise => { + return async (callCluster: LegacyAPICaller): Promise => { const [response, config] = await Promise.all([ callCluster('get', { index, diff --git a/src/plugins/data/server/saved_objects/index_patterns.ts b/src/plugins/data/server/saved_objects/index_patterns.ts index ee02f38427914f..902cf2988f429f 100644 --- a/src/plugins/data/server/saved_objects/index_patterns.ts +++ b/src/plugins/data/server/saved_objects/index_patterns.ts @@ -37,7 +37,7 @@ export const indexPatternSavedObjectType: SavedObjectsType = { getInAppUrl(obj) { return { path: `/app/management/kibana/indexPatterns/patterns/${encodeURIComponent(obj.id)}`, - uiCapabilitiesPath: 'management.kibana.index_patterns', + uiCapabilitiesPath: 'management.kibana.indexPatterns', }; }, }, diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 136d960b52c347..24ce42e2c20aec 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -4,7 +4,6 @@ ```ts -import { APICaller as APICaller_2 } from 'kibana/server'; import Boom from 'boom'; import { BulkIndexDocumentsParams } from 'elasticsearch'; import { CatAliasesParams } from 'elasticsearch'; @@ -92,6 +91,7 @@ import { IngestGetPipelineParams } from 'elasticsearch'; import { IngestPutPipelineParams } from 'elasticsearch'; import { IngestSimulateParams } from 'elasticsearch'; import { KibanaConfigType as KibanaConfigType_2 } from 'src/core/server/kibana_config'; +import { LegacyAPICaller as LegacyAPICaller_2 } from 'kibana/server'; import { Logger as Logger_2 } from 'kibana/server'; import { MGetParams } from 'elasticsearch'; import { MGetResponse } from 'elasticsearch'; @@ -109,7 +109,7 @@ import { PeerCertificate } from 'tls'; import { PingParams } from 'elasticsearch'; import { PutScriptParams } from 'elasticsearch'; import { PutTemplateParams } from 'elasticsearch'; -import { RecursiveReadonly } from 'kibana/public'; +import { RecursiveReadonly } from '@kbn/utility-types'; import { ReindexParams } from 'elasticsearch'; import { ReindexRethrottleParams } from 'elasticsearch'; import { RenderSearchTemplateParams } from 'elasticsearch'; @@ -335,6 +335,14 @@ export function getDefaultSearchParams(config: SharedGlobalConfig): { restTotalHitsAsInt: boolean; }; +// Warning: (ae-missing-release-tag) "getTime" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, options?: { + forceNow?: Date; + fieldName?: string; +}): import("../..").RangeFilter | undefined; + // @internal export function getTotalLoaded({ total, failed, successful }: ShardsResponse): { total: number; @@ -477,7 +485,7 @@ export const indexPatterns: { // // @public (undocumented) export class IndexPatternsFetcher { - constructor(callDataCluster: APICaller_2); + constructor(callDataCluster: LegacyAPICaller_2); getFieldsForTimePattern(options: { pattern: string; metaFields: string[]; diff --git a/src/plugins/discover/public/application/_discover.scss b/src/plugins/discover/public/application/_discover.scss index b0f3dfaf96c4f3..1aaa0a24357edd 100644 --- a/src/plugins/discover/public/application/_discover.scss +++ b/src/plugins/discover/public/application/_discover.scss @@ -100,16 +100,6 @@ discover-app { .dscSkipButton { position: absolute; - left: -10000px; + right: $euiSizeM; top: $euiSizeXS; - width: 1px; - height: 1px; - overflow: hidden; - - &:focus { - left: initial; - right: $euiSize; - width: auto; - height: auto; - } } diff --git a/src/plugins/discover/public/application/angular/discover.html b/src/plugins/discover/public/application/angular/discover.html index 022c39afff27f5..3c16e4a6d9deee 100644 --- a/src/plugins/discover/public/application/angular/discover.html +++ b/src/plugins/discover/public/application/angular/discover.html @@ -65,18 +65,7 @@

{{screenTitle}}

- + {{screenTitle}} on-remove-column="removeColumn" > - +
{ + bottomMarker.focus(); + // The anchor tag is not technically empty (it's a hack to make Safari scroll) + // so the browser will show a highlight: remove the focus once scrolled + $timeout(() => { + bottomMarker.blur(); + }, 0); + }, 0); + }; + $scope.newQuery = function () { history.push('/'); }; @@ -1007,17 +1023,6 @@ function discoverController( $window.scrollTo(0, 0); }; - $scope.scrollToBottom = function () { - // delay scrolling to after the rows have been rendered - $timeout(() => { - $element.find('#discoverBottomMarker').focus(); - }, 0); - }; - - $scope.showAllRows = function () { - $scope.minimumVisibleRows = $scope.hits; - }; - async function setupVisualization() { // If no timefield has been specified we don't create a histogram of messages if (!getTimeField()) return; diff --git a/src/plugins/visualize/public/application/editor/lib/index.ts b/src/plugins/discover/public/application/components/skip_bottom_button/index.ts similarity index 80% rename from src/plugins/visualize/public/application/editor/lib/index.ts rename to src/plugins/discover/public/application/components/skip_bottom_button/index.ts index 78589383925fb9..2feaa35e0d61f7 100644 --- a/src/plugins/visualize/public/application/editor/lib/index.ts +++ b/src/plugins/discover/public/application/components/skip_bottom_button/index.ts @@ -17,6 +17,5 @@ * under the License. */ -export { useVisualizeAppState } from './visualize_app_state'; -export { makeStateful } from './make_stateful'; -export { addEmbeddableToDashboardUrl } from '../../../../../dashboard/public/'; +export { SkipBottomButton } from './skip_bottom_button'; +export { createSkipBottomButtonDirective } from './skip_bottom_button_directive'; diff --git a/src/plugins/visualize/public/application/help_menu/help_menu_util.js b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx similarity index 54% rename from src/plugins/visualize/public/application/help_menu/help_menu_util.js rename to src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx index c297326f2e264e..bf417f9f1890b6 100644 --- a/src/plugins/visualize/public/application/help_menu/help_menu_util.js +++ b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx @@ -16,19 +16,26 @@ * specific language governing permissions and limitations * under the License. */ +import React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ReactWrapper } from 'enzyme'; +import { SkipBottomButton, SkipBottomButtonProps } from './skip_bottom_button'; +// @ts-ignore +import { findTestSubject } from '@elastic/eui/lib/test'; -import { i18n } from '@kbn/i18n'; +describe('Skip to Bottom Button', function () { + let props: SkipBottomButtonProps; + let component: ReactWrapper; -export function addHelpMenuToAppChrome(chrome, docLinks) { - chrome.setHelpExtension({ - appName: i18n.translate('visualize.helpMenu.appName', { - defaultMessage: 'Visualize', - }), - links: [ - { - linkType: 'documentation', - href: `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/visualize.html`, - }, - ], + beforeAll(() => { + props = { + onClick: jest.fn(), + }; }); -} + + it('should be clickable', function () { + component = mountWithIntl(); + component.simulate('click'); + expect(props.onClick).toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.tsx b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.tsx new file mode 100644 index 00000000000000..ccf05ca031a8da --- /dev/null +++ b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.tsx @@ -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 React from 'react'; +import { EuiSkipLink } from '@elastic/eui'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; + +export interface SkipBottomButtonProps { + /** + * Action to perform on click + */ + onClick: () => void; +} + +export function SkipBottomButton({ onClick }: SkipBottomButtonProps) { + return ( + + { + // prevent the anchor to reload the page on click + event.preventDefault(); + // The destinationId prop cannot be leveraged here as the table needs + // to be updated first (angular logic) + onClick(); + }} + className="dscSkipButton" + destinationId="" + > + + + + ); +} diff --git a/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.ts b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.ts new file mode 100644 index 00000000000000..27f17b25fd447c --- /dev/null +++ b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.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. + */ +import { SkipBottomButton } from './skip_bottom_button'; + +export function createSkipBottomButtonDirective(reactDirective: any) { + return reactDirective(SkipBottomButton, [['onClick', { watchDepth: 'reference' }]]); +} diff --git a/src/plugins/discover/public/get_inner_angular.ts b/src/plugins/discover/public/get_inner_angular.ts index 2b4705645cfccd..05513eef936247 100644 --- a/src/plugins/discover/public/get_inner_angular.ts +++ b/src/plugins/discover/public/get_inner_angular.ts @@ -63,6 +63,7 @@ import { createLoadingSpinnerDirective } from '././application/components/loadin import { createTimechartHeaderDirective } from './application/components/timechart_header'; import { DiscoverStartPlugins } from './plugin'; import { getScopedHistory } from './kibana_services'; +import { createSkipBottomButtonDirective } from './application/components/skip_bottom_button'; /** * returns the main inner angular module, it contains all the parts of Angular Discover @@ -155,6 +156,7 @@ export function initializeInnerAngularModule( .directive('fixedScroll', FixedScrollProvider) .directive('renderComplete', createRenderCompleteDirective) .directive('discoverSidebar', createDiscoverSidebarDirective) + .directive('skipBottomButton', createSkipBottomButtonDirective) .directive('hitsCounter', createHitsCounterDirective) .directive('loadingSpinner', createLoadingSpinnerDirective) .directive('timechartHeader', createTimechartHeaderDirective) diff --git a/src/plugins/expressions/server/legacy.ts b/src/plugins/expressions/server/legacy.ts index 4dd9419e59e2dd..8ff08542f18f85 100644 --- a/src/plugins/expressions/server/legacy.ts +++ b/src/plugins/expressions/server/legacy.ts @@ -26,7 +26,7 @@ import { register, registryFactory, Registry, Fn } from '@kbn/interpreter/common import Boom from 'boom'; import { schema } from '@kbn/config-schema'; -import { CoreSetup, Logger, APICaller } from 'src/core/server'; +import { CoreSetup, Logger, LegacyAPICaller } from 'src/core/server'; import { ExpressionsServerSetupDependencies } from './plugin'; import { typeSpecs, ExpressionType } from '../common'; import { serializeProvider } from '../common'; @@ -98,7 +98,7 @@ export const createLegacyServerEndpoints = ( * @param {*} fnCall - Describes the function being run `{ functionName, args, context }` */ async function runFunction( - handlers: { environment: string; elasticsearchClient: APICaller }, + handlers: { environment: string; elasticsearchClient: LegacyAPICaller }, fnCall: any ) { const { functionName, args, context } = fnCall; diff --git a/src/plugins/home/server/capabilities_provider.ts b/src/plugins/home/server/capabilities_provider.ts index 1c662e2301e16c..5e86e0ca54bf79 100644 --- a/src/plugins/home/server/capabilities_provider.ts +++ b/src/plugins/home/server/capabilities_provider.ts @@ -24,6 +24,6 @@ export const capabilitiesProvider = () => ({ visualize: true, console: true, advanced_settings: true, - index_patterns: true, + indexPatterns: true, }, }); diff --git a/src/plugins/index_pattern_management/public/plugin.ts b/src/plugins/index_pattern_management/public/plugin.ts index a98cc05a0a80af..6e93d23f8469ca 100644 --- a/src/plugins/index_pattern_management/public/plugin.ts +++ b/src/plugins/index_pattern_management/public/plugin.ts @@ -27,7 +27,7 @@ import { IndexPatternManagementServiceStart, } from './service'; -import { ManagementSetup, ManagementApp, ManagementSectionId } from '../../management/public'; +import { ManagementSetup, ManagementSectionId } from '../../management/public'; export interface IndexPatternManagementSetupDependencies { management: ManagementSetup; @@ -57,7 +57,6 @@ export class IndexPatternManagementPlugin IndexPatternManagementStartDependencies > { private readonly indexPatternManagementService = new IndexPatternManagementService(); - private managementApp?: ManagementApp; constructor(initializerContext: PluginInitializerContext) {} @@ -80,7 +79,7 @@ export class IndexPatternManagementPlugin return pathInApp && `/patterns${pathInApp}`; }); - this.managementApp = kibanaSection.registerApp({ + kibanaSection.registerApp({ id: IPM_APP_ID, title: sectionsHeader, order: 0, @@ -95,10 +94,6 @@ export class IndexPatternManagementPlugin } public start(core: CoreStart, plugins: IndexPatternManagementStartDependencies) { - if (!core.application.capabilities.management.kibana.index_patterns) { - this.managementApp!.disable(); - } - return this.indexPatternManagementService.start(); } diff --git a/src/plugins/input_control_vis/public/input_control_vis_type.ts b/src/plugins/input_control_vis/public/input_control_vis_type.ts index 8114dbf110f8b3..2af53ea4d28e83 100644 --- a/src/plugins/input_control_vis/public/input_control_vis_type.ts +++ b/src/plugins/input_control_vis/public/input_control_vis_type.ts @@ -23,7 +23,6 @@ import { createInputControlVisController } from './vis_controller'; import { getControlsTab } from './components/editor/controls_tab'; import { OptionsTab } from './components/editor/options_tab'; import { InputControlVisDependencies } from './plugin'; -import { defaultFeedbackMessage } from '../../kibana_utils/public'; export function createInputControlVisTypeDefinition(deps: InputControlVisDependencies) { const InputControlVisController = createInputControlVisController(deps); @@ -39,7 +38,6 @@ export function createInputControlVisTypeDefinition(deps: InputControlVisDepende defaultMessage: 'Create interactive controls for easy dashboard manipulation.', }), stage: 'experimental', - feedbackMessage: defaultFeedbackMessage, visualization: InputControlVisController, visConfig: { defaults: { diff --git a/src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx b/src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx index 8187e70b1bbd1a..63b9b48ec809eb 100644 --- a/src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx +++ b/src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx @@ -17,7 +17,7 @@ * under the License. */ import { i18n } from '@kbn/i18n'; -import React, { Component, createRef } from 'react'; +import React, { Component } from 'react'; import { EuiFormRow, EuiDualRange } from '@elastic/eui'; import { EuiFormRowDisplayKeys } from '@elastic/eui/src/components/form/form_row/form_row'; import { EuiDualRangeProps } from '@elastic/eui/src/components/form/range/dual_range'; @@ -72,18 +72,6 @@ export class ValidatedDualRange extends Component { return null; } - // Can remove after eui#3412 is resolved - componentDidMount() { - if (this.trackRef.current) { - const track = this.trackRef.current.querySelector('.euiRangeTrack'); - if (track) { - track.setAttribute('aria-hidden', 'true'); - } - } - } - - trackRef = createRef(); - // @ts-ignore state populated by getDerivedStateFromProps state: State = {}; @@ -119,34 +107,32 @@ export class ValidatedDualRange extends Component { } = this.props; return ( -
- + - - -
+ value={this.state.value} + onChange={this._onChange} + minInputProps={{ + 'aria-label': i18n.translate('kibana-react.dualRangeControl.minInputAriaLabel', { + defaultMessage: 'Range minimum', + }), + }} + maxInputProps={{ + 'aria-label': i18n.translate('kibana-react.dualRangeControl.maxInputAriaLabel', { + defaultMessage: 'Range maximum', + }), + }} + {...rest} + /> + ); } } diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts index 804c8b0ed2026e..1adc0dc6896fda 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts @@ -27,7 +27,7 @@ */ import { snakeCase } from 'lodash'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; const TYPES = [ 'dashboard', @@ -45,7 +45,7 @@ export interface KibanaSavedObjectCounts { } export async function getSavedObjectsCounts( - callCluster: APICaller, + callCluster: LegacyAPICaller, kibanaIndex: string // Typically '.kibana'. We might need a way to obtain it from the SavedObjects client (or the SavedObjects client to provide a way to run aggregations?) ): Promise { const savedObjectCountSearchParams = { diff --git a/src/plugins/kibana_utils/common/default_feedback_message.ts b/src/plugins/kibana_utils/common/default_feedback_message.ts deleted file mode 100644 index f61f36bc8810cc..00000000000000 --- a/src/plugins/kibana_utils/common/default_feedback_message.ts +++ /dev/null @@ -1,28 +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 { i18n } from '@kbn/i18n'; - -export const defaultFeedbackMessage = i18n.translate('kibana_utils.defaultFeedbackMessage', { - defaultMessage: 'Have feedback? Please create an issue in {link}.', - values: { - link: - 'GitHub', - }, -}); diff --git a/src/plugins/kibana_utils/common/index.ts b/src/plugins/kibana_utils/common/index.ts index 99daed98dbe640..c94021872b4e10 100644 --- a/src/plugins/kibana_utils/common/index.ts +++ b/src/plugins/kibana_utils/common/index.ts @@ -28,4 +28,3 @@ export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_w export { url } from './url'; export { now } from './now'; export { calculateObjectHash } from './calculate_object_hash'; -export { defaultFeedbackMessage } from './default_feedback_message'; diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 6f61e2c228970d..2911a9ae75689d 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -31,7 +31,6 @@ export { UiComponentInstance, url, createGetterSetter, - defaultFeedbackMessage, } from '../common'; export * from './core'; export * from '../common/errors'; diff --git a/src/plugins/management/public/management_sections_service.test.ts b/src/plugins/management/public/management_sections_service.test.ts index 2c5d04883235c7..fd56dd8a6ee274 100644 --- a/src/plugins/management/public/management_sections_service.test.ts +++ b/src/plugins/management/public/management_sections_service.test.ts @@ -27,9 +27,15 @@ describe('ManagementService', () => { managementService = new ManagementSectionsService(); }); + const capabilities = { + navLinks: {}, + catalogue: {}, + management: {}, + }; + test('Provides default sections', () => { managementService.setup(); - const start = managementService.start(); + const start = managementService.start({ capabilities }); expect(start.getAllSections().length).toEqual(6); expect(start.getSection(ManagementSectionId.Ingest)).toBeDefined(); @@ -48,7 +54,7 @@ describe('ManagementService', () => { expect(setup.getSection('test-section')).not.toBeUndefined(); // Start phase: - const start = managementService.start(); + const start = managementService.start({ capabilities }); expect(start.getSectionsEnabled().length).toEqual(7); @@ -56,4 +62,38 @@ describe('ManagementService', () => { expect(start.getSectionsEnabled().length).toEqual(6); }); + + test('Disables items that are not allowed by Capabilities', () => { + // Setup phase: + const setup = managementService.setup(); + const testSection = setup.register({ id: 'test-section', title: 'Test Section' }); + testSection.registerApp({ id: 'test-app-1', title: 'Test App 1', mount: jest.fn() }); + testSection.registerApp({ id: 'test-app-2', title: 'Test App 2', mount: jest.fn() }); + testSection.registerApp({ id: 'test-app-3', title: 'Test App 3', mount: jest.fn() }); + + expect(setup.getSection('test-section')).not.toBeUndefined(); + + // Start phase: + managementService.start({ + capabilities: { + navLinks: {}, + catalogue: {}, + management: { + ['test-section']: { + 'test-app-1': true, + 'test-app-2': false, + // test-app-3 intentionally left undefined. Should be enabled by default + }, + }, + }, + }); + + expect(testSection.apps).toHaveLength(3); + expect(testSection.getAppsEnabled().map((app) => app.id)).toMatchInlineSnapshot(` + Array [ + "test-app-1", + "test-app-3", + ] + `); + }); }); diff --git a/src/plugins/management/public/management_sections_service.ts b/src/plugins/management/public/management_sections_service.ts index 08a87b3e89f2ba..d8d148a9247fff 100644 --- a/src/plugins/management/public/management_sections_service.ts +++ b/src/plugins/management/public/management_sections_service.ts @@ -21,7 +21,12 @@ import { ReactElement } from 'react'; import { ManagementSection, RegisterManagementSectionArgs } from './utils'; import { managementSections } from './components/management_sections'; -import { ManagementSectionId, SectionsServiceSetup, SectionsServiceStart } from './types'; +import { + ManagementSectionId, + SectionsServiceSetup, + SectionsServiceStart, + SectionsServiceStartDeps, +} from './types'; export class ManagementSectionsService { private sections: Map = new Map(); @@ -55,7 +60,18 @@ export class ManagementSectionsService { }; } - start(): SectionsServiceStart { + start({ capabilities }: SectionsServiceStartDeps): SectionsServiceStart { + this.getAllSections().forEach((section) => { + if (capabilities.management.hasOwnProperty(section.id)) { + const sectionCapabilities = capabilities.management[section.id]; + section.apps.forEach((app) => { + if (sectionCapabilities.hasOwnProperty(app.id) && sectionCapabilities[app.id] !== true) { + app.disable(); + } + }); + } + }); + return { getSection: this.getSection, getAllSections: this.getAllSections, diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 71656d7c0b83ba..dada4636e6add9 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -82,7 +82,7 @@ export class ManagementPlugin implements Plugin ManagementSection; + register: (args: Omit) => ManagementSection; getSection: (sectionId: ManagementSectionId | string) => ManagementSection; } diff --git a/src/plugins/management/server/capabilities_provider.ts b/src/plugins/management/server/capabilities_provider.ts index 9a69749c8233b4..254ac3ed04dd73 100644 --- a/src/plugins/management/server/capabilities_provider.ts +++ b/src/plugins/management/server/capabilities_provider.ts @@ -25,7 +25,7 @@ export const capabilitiesProvider = () => ({ */ kibana: { settings: true, - index_patterns: true, + indexPatterns: true, objects: true, }, }, diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx index 2b7466ffd6ab37..a1653c52892554 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx @@ -19,7 +19,7 @@ import { ButtonIconSide } from '@elastic/eui'; -export type TopNavMenuAction = (anchorElement: EventTarget) => void; +export type TopNavMenuAction = (anchorElement: HTMLElement) => void; export interface TopNavMenuData { id?: string; @@ -29,7 +29,7 @@ export interface TopNavMenuData { testId?: string; className?: string; disableButton?: boolean | (() => boolean); - tooltip?: string | (() => string); + tooltip?: string | (() => string | undefined); emphasize?: boolean; iconType?: string; iconSide?: ButtonIconSide; diff --git a/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts b/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts index 53ef1f3f04ad9b..9e7346f3b673cd 100644 --- a/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts +++ b/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts @@ -51,14 +51,17 @@ export class SavedObjectLoader { } /** - * Retrieve a saved object by id. Returns a promise that completes when the object finishes + * Retrieve a saved object by id or create new one. + * Returns a promise that completes when the object finishes * initializing. - * @param id + * @param opts * @returns {Promise} */ - async get(id?: string) { + async get(opts?: Record | string) { + // can accept object as argument in accordance to SavedVis class + // see src/plugins/saved_objects/public/saved_object/saved_object_loader.ts // @ts-ignore - const obj = new this.Class(id); + const obj = new this.Class(opts); return obj.init(); } diff --git a/src/plugins/saved_objects/public/types.ts b/src/plugins/saved_objects/public/types.ts index 973a493c0a15e9..6db72b396a86ae 100644 --- a/src/plugins/saved_objects/public/types.ts +++ b/src/plugins/saved_objects/public/types.ts @@ -63,6 +63,7 @@ export interface SavedObjectSaveOpts { confirmOverwrite?: boolean; isTitleDuplicateConfirmed?: boolean; onTitleDuplicate?: () => void; + returnToOrigin?: boolean; } export interface SavedObjectCreationOpts { diff --git a/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts index 09e08e6ec333b0..e83952e82c953e 100644 --- a/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts +++ b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts @@ -70,7 +70,7 @@ describe('canViewInApp', () => { let uiCapabilities = createCapabilities({ management: { kibana: { - index_patterns: true, + indexPatterns: true, }, }, }); @@ -81,7 +81,7 @@ describe('canViewInApp', () => { uiCapabilities = createCapabilities({ management: { kibana: { - index_patterns: false, + indexPatterns: false, }, }, }); diff --git a/src/plugins/saved_objects_management/public/lib/in_app_url.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.ts index 82146554afa6ff..0fcf52cba254b5 100644 --- a/src/plugins/saved_objects_management/public/lib/in_app_url.ts +++ b/src/plugins/saved_objects_management/public/lib/in_app_url.ts @@ -30,7 +30,7 @@ export function canViewInApp(uiCapabilities: Capabilities, type: string): boolea case 'index-pattern': case 'index-patterns': case 'indexPatterns': - return uiCapabilities.management.kibana.index_patterns as boolean; + return uiCapabilities.management.kibana.indexPatterns as boolean; case 'dashboard': case 'dashboards': return uiCapabilities.dashboard.show as boolean; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx index fd7967f4128c3a..50358c17e058c3 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx @@ -18,14 +18,7 @@ */ import React, { PureComponent } from 'react'; -import { - EuiFieldNumber, - EuiFieldText, - EuiFormRow, - EuiSwitch, - // @ts-ignore - EuiCodeEditor, -} from '@elastic/eui'; +import { EuiFieldNumber, EuiFieldText, EuiFormRow, EuiSwitch, EuiCodeEditor } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { FieldState, FieldType } from '../../types'; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index 884f39b97e2335..7d43158ad8878e 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -304,7 +304,7 @@ exports[`SavedObjectsTable should render normally 1`] = ` "icon": "indexPatternApp", "inAppUrl": Object { "path": "/management/kibana/indexPatterns/patterns/1", - "uiCapabilitiesPath": "management.kibana.index_patterns", + "uiCapabilitiesPath": "management.kibana.indexPatterns", }, "title": "MyIndexPattern*", }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap index 6eb9e36394ee31..15e5cb89b622c6 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap @@ -456,7 +456,7 @@ exports[`Relationships should render searches normally 1`] = ` "icon": "indexPatternApp", "inAppUrl": Object { "path": "/app/management/kibana/indexPatterns/patterns/1", - "uiCapabilitiesPath": "management.kibana.index_patterns", + "uiCapabilitiesPath": "management.kibana.indexPatterns", }, "title": "My Index Pattern", }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap index 92e4e637e0d3fe..56fddc075a50c9 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap @@ -178,7 +178,7 @@ exports[`Table prevents saved objects from being deleted 1`] = ` "icon": "indexPatternApp", "inAppUrl": Object { "path": "/management/kibana/indexPatterns/patterns/1", - "uiCapabilitiesPath": "management.kibana.index_patterns", + "uiCapabilitiesPath": "management.kibana.indexPatterns", }, "title": "MyIndexPattern*", }, @@ -393,7 +393,7 @@ exports[`Table should render normally 1`] = ` "icon": "indexPatternApp", "inAppUrl": Object { "path": "/management/kibana/indexPatterns/patterns/1", - "uiCapabilitiesPath": "management.kibana.index_patterns", + "uiCapabilitiesPath": "management.kibana.indexPatterns", }, "title": "MyIndexPattern*", }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index 6e7397d1058bf8..aac799da6ea67e 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -31,7 +31,6 @@ import { EuiForm, EuiFormRow, EuiSwitch, - // @ts-ignore EuiFilePicker, EuiInMemoryTable, EuiSelect, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx index 9277d9b00305b1..2e545b372f781b 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx @@ -77,7 +77,7 @@ describe('Relationships', () => { editUrl: '#/management/kibana/indexPatterns/patterns/1', inAppUrl: { path: '/management/kibana/indexPatterns/patterns/1', - uiCapabilitiesPath: 'management.kibana.index_patterns', + uiCapabilitiesPath: 'management.kibana.indexPatterns', }, }, }, @@ -113,7 +113,7 @@ describe('Relationships', () => { icon: 'indexPatternApp', inAppUrl: { path: '/app/management/kibana/indexPatterns/patterns/1', - uiCapabilitiesPath: 'management.kibana.index_patterns', + uiCapabilitiesPath: 'management.kibana.indexPatterns', }, title: 'My Index Pattern', }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx index b9dad983cb42d4..6b209a62e1b98b 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers'; -// @ts-ignore +// @ts-expect-error import { findTestSubject } from '@elastic/eui/lib/test'; import { keyCodes } from '@elastic/eui'; import { httpServiceMock } from '../../../../../../core/public/mocks'; @@ -41,7 +41,7 @@ const defaultProps: TableProps = { editUrl: '#/management/kibana/indexPatterns/patterns/1', inAppUrl: { path: '/management/kibana/indexPatterns/patterns/1', - uiCapabilitiesPath: 'management.kibana.index_patterns', + uiCapabilitiesPath: 'management.kibana.indexPatterns', }, }, }, @@ -68,7 +68,7 @@ const defaultProps: TableProps = { editUrl: '#/management/kibana/indexPatterns/patterns/1', inAppUrl: { path: '/management/kibana/indexPatterns/patterns/1', - uiCapabilitiesPath: 'management.kibana.index_patterns', + uiCapabilitiesPath: 'management.kibana.indexPatterns', }, }, }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx index 51e7525d0e00a1..719729cee26025 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx @@ -20,7 +20,6 @@ import { IBasePath } from 'src/core/public'; import React, { PureComponent, Fragment } from 'react'; import { - // @ts-ignore EuiSearchBar, EuiBasicTable, EuiButton, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx index e3456240dc340f..3719dac24e6e70 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx @@ -158,7 +158,7 @@ describe('SavedObjectsTable', () => { editUrl: '#/management/kibana/indexPatterns/patterns/1', inAppUrl: { path: '/management/kibana/indexPatterns/patterns/1', - uiCapabilitiesPath: 'management.kibana.index_patterns', + uiCapabilitiesPath: 'management.kibana.indexPatterns', }, }, }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx index 54bc649c33b60b..340c0e3237f91f 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx @@ -19,7 +19,7 @@ import React, { Component } from 'react'; import { debounce } from 'lodash'; -// @ts-ignore +// @ts-expect-error import { saveAs } from '@elastic/filesaver'; import { EuiSpacer, diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index 9422df60305184..75cfac721bcd3b 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -29,7 +29,7 @@ import { SavedObjectsClientContract, SavedObjectsClient, CoreStart, - ICustomClusterClient, + ILegacyCustomClusterClient, } from '../../../core/server'; import { getTelemetryOptIn, @@ -63,7 +63,7 @@ export class FetcherTask { private isSending = false; private internalRepository?: SavedObjectsClientContract; private telemetryCollectionManager?: TelemetryCollectionManagerPluginStart; - private elasticsearchClient?: ICustomClusterClient; + private elasticsearchClient?: ILegacyCustomClusterClient; constructor(initializerContext: PluginInitializerContext) { this.config$ = initializerContext.config.create(); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.ts b/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.ts index d5f0d2d8c9598d..4a33356ee97614 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.ts @@ -17,7 +17,7 @@ * under the License. */ -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; // This can be removed when the ES client improves the types export interface ESClusterInfo { @@ -43,6 +43,6 @@ export interface ESClusterInfo { * * @param {function} callCluster The callWithInternalUser handler (exposed for testing) */ -export function getClusterInfo(callCluster: APICaller) { +export function getClusterInfo(callCluster: LegacyAPICaller) { return callCluster('info'); } diff --git a/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.ts b/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.ts index 89e2cae7779856..d7c0110a99c6fd 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.ts @@ -18,14 +18,14 @@ */ import { ClusterDetailsGetter } from 'src/plugins/telemetry_collection_manager/server'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { TIMEOUT } from './constants'; /** * Get the cluster stats from the connected cluster. * * This is the equivalent to GET /_cluster/stats?timeout=30s. */ -export async function getClusterStats(callCluster: APICaller) { +export async function getClusterStats(callCluster: LegacyAPICaller) { return await callCluster('cluster.stats', { timeout: TIMEOUT, }); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts b/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts index 645c5a4be8a6cb..5d27774a630a59 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts @@ -19,7 +19,7 @@ import { omit } from 'lodash'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { StatsCollectionContext } from 'src/plugins/telemetry_collection_manager/server'; export interface KibanaUsageStats { @@ -83,7 +83,7 @@ export function handleKibanaStats( export async function getKibana( usageCollection: UsageCollectionSetup, - callWithInternalUser: APICaller + callWithInternalUser: LegacyAPICaller ): Promise { const usage = await usageCollection.bulkFetch(callWithInternalUser); return usageCollection.toObject(usage); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_license.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_license.ts index 0ba6fcc154d8bd..d41904c6d8e0e8 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_license.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_license.ts @@ -17,12 +17,12 @@ * under the License. */ -import { APICaller } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { ESLicense, LicenseGetter } from 'src/plugins/telemetry_collection_manager/server'; let cachedLicense: ESLicense | undefined; -function fetchLicense(callCluster: APICaller, local: boolean) { +function fetchLicense(callCluster: LegacyAPICaller, local: boolean) { return callCluster<{ license: ESLicense }>('transport.request', { method: 'GET', path: '/_license', @@ -41,7 +41,7 @@ function fetchLicense(callCluster: APICaller, local: boolean) { * * Like any X-Pack related API, X-Pack must installed for this to work. */ -async function getLicenseFromLocalOrMaster(callCluster: APICaller) { +async function getLicenseFromLocalOrMaster(callCluster: LegacyAPICaller) { // Fetching the local license is cheaper than getting it from the master and good enough const { license } = await fetchLicense(callCluster, true).catch(async (err) => { if (cachedLicense) { diff --git a/src/plugins/telemetry/server/telemetry_collection/register_collection.ts b/src/plugins/telemetry/server/telemetry_collection/register_collection.ts index 833fd9f7fd5bca..438fcadad92555 100644 --- a/src/plugins/telemetry/server/telemetry_collection/register_collection.ts +++ b/src/plugins/telemetry/server/telemetry_collection/register_collection.ts @@ -36,7 +36,7 @@ * under the License. */ -import { IClusterClient } from 'kibana/server'; +import { ILegacyClusterClient } from 'kibana/server'; import { TelemetryCollectionManagerPluginSetup } from 'src/plugins/telemetry_collection_manager/server'; import { getLocalStats } from './get_local_stats'; import { getClusterUuids } from './get_cluster_stats'; @@ -44,7 +44,7 @@ import { getLocalLicense } from './get_local_license'; export function registerCollection( telemetryCollectionManager: TelemetryCollectionManagerPluginSetup, - esCluster: IClusterClient + esCluster: ILegacyClusterClient ) { telemetryCollectionManager.setCollection({ esCluster, diff --git a/src/plugins/telemetry_collection_manager/server/types.ts b/src/plugins/telemetry_collection_manager/server/types.ts index d3a47694d38a76..16f96c07fd8ead 100644 --- a/src/plugins/telemetry_collection_manager/server/types.ts +++ b/src/plugins/telemetry_collection_manager/server/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { APICaller, Logger, KibanaRequest, IClusterClient } from 'kibana/server'; +import { LegacyAPICaller, Logger, KibanaRequest, ILegacyClusterClient } from 'kibana/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { TelemetryCollectionManagerPlugin } from './plugin'; @@ -64,7 +64,7 @@ export interface ClusterDetails { export interface StatsCollectionConfig { usageCollection: UsageCollectionSetup; - callCluster: APICaller; + callCluster: LegacyAPICaller; start: string | number; end: string | number; } @@ -129,7 +129,7 @@ export interface CollectionConfig< > { title: string; priority: number; - esCluster: IClusterClient; + esCluster: ILegacyClusterClient; statsGetter: StatsGetter; clusterDetailsGetter: ClusterDetailsGetter; licenseGetter: LicenseGetter; @@ -144,6 +144,6 @@ export interface Collection< statsGetter: StatsGetter; licenseGetter: LicenseGetter; clusterDetailsGetter: ClusterDetailsGetter; - esCluster: IClusterClient; + esCluster: ILegacyClusterClient; title: string; } diff --git a/src/plugins/usage_collection/server/collector/collector.ts b/src/plugins/usage_collection/server/collector/collector.ts index 00d55ef1c06db5..9ae63b9f50e429 100644 --- a/src/plugins/usage_collection/server/collector/collector.ts +++ b/src/plugins/usage_collection/server/collector/collector.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Logger, APICaller } from 'kibana/server'; +import { Logger, LegacyAPICaller } from 'kibana/server'; export type CollectorFormatForBulkUpload = (result: T) => { type: string; payload: U }; @@ -48,7 +48,7 @@ export interface CollectorOptions { type: string; init?: Function; schema?: MakeSchemaFrom; - fetch: (callCluster: APICaller) => Promise | T; + fetch: (callCluster: LegacyAPICaller) => Promise | T; /* * A hook for allowing the fetched data payload to be organized into a typed * data model for internal bulk upload. See defaultFormatterForBulkUpload for diff --git a/src/plugins/usage_collection/server/collector/collector_set.ts b/src/plugins/usage_collection/server/collector/collector_set.ts index 04ba7452f99e2d..b6308d66033885 100644 --- a/src/plugins/usage_collection/server/collector/collector_set.ts +++ b/src/plugins/usage_collection/server/collector/collector_set.ts @@ -18,7 +18,7 @@ */ import { snakeCase } from 'lodash'; -import { Logger, APICaller } from 'kibana/server'; +import { Logger, LegacyAPICaller } from 'kibana/server'; import { Collector, CollectorOptions } from './collector'; import { UsageCollector } from './usage_collector'; @@ -112,7 +112,7 @@ export class CollectorSet { }; public bulkFetch = async ( - callCluster: APICaller, + callCluster: LegacyAPICaller, collectors: Array> = this.collectors ) => { const responses = []; @@ -140,7 +140,7 @@ export class CollectorSet { return this.makeCollectorSetFromArray(filtered); }; - public bulkFetchUsage = async (callCluster: APICaller) => { + public bulkFetchUsage = async (callCluster: LegacyAPICaller) => { const usageCollectors = this.getFilteredCollectorSet((c) => c instanceof UsageCollector); return await this.bulkFetch(callCluster, usageCollectors.collectors); }; diff --git a/src/plugins/vis_default_editor/public/components/sidebar/sidebar.tsx b/src/plugins/vis_default_editor/public/components/sidebar/sidebar.tsx index 837dd9bff2c6de..c41315e7bc0dca 100644 --- a/src/plugins/vis_default_editor/public/components/sidebar/sidebar.tsx +++ b/src/plugins/vis_default_editor/public/components/sidebar/sidebar.tsx @@ -23,9 +23,13 @@ import { i18n } from '@kbn/i18n'; import { keyCodes, EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { EventEmitter } from 'events'; -import { Vis, PersistedState } from 'src/plugins/visualizations/public'; -import { SavedSearch } from 'src/plugins/discover/public'; +import { + Vis, + PersistedState, + VisualizeEmbeddableContract, +} from 'src/plugins/visualizations/public'; import { TimeRange } from 'src/plugins/data/public'; +import { SavedObject } from 'src/plugins/saved_objects/public'; import { DefaultEditorNavBar, OptionTab } from './navbar'; import { DefaultEditorControls } from './controls'; import { setStateParamValue, useEditorReducer, useEditorFormState, discardChanges } from './state'; @@ -34,6 +38,7 @@ import { SidebarTitle } from './sidebar_title'; import { Schema } from '../../schemas'; interface DefaultEditorSideBarProps { + embeddableHandler: VisualizeEmbeddableContract; isCollapsed: boolean; onClickCollapse: () => void; optionTabs: OptionTab[]; @@ -41,11 +46,12 @@ interface DefaultEditorSideBarProps { vis: Vis; isLinkedSearch: boolean; eventEmitter: EventEmitter; - savedSearch?: SavedSearch; + savedSearch?: SavedObject; timeRange: TimeRange; } function DefaultEditorSideBar({ + embeddableHandler, isCollapsed, onClickCollapse, optionTabs, @@ -104,12 +110,12 @@ function DefaultEditorSideBar({ aggs: state.data.aggs ? (state.data.aggs.aggs.map((agg) => agg.toJSON()) as any) : [], }, }); - eventEmitter.emit('updateVis'); + embeddableHandler.reload(); eventEmitter.emit('dirtyStateChange', { isDirty: false, }); setTouched(false); - }, [vis, state, formState.invalid, setTouched, isDirty, eventEmitter]); + }, [vis, state, formState.invalid, setTouched, isDirty, eventEmitter, embeddableHandler]); const onSubmit: KeyboardEventHandler = useCallback( (event) => { diff --git a/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx b/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx index ebc92170c87350..6713c2ce2391be 100644 --- a/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx +++ b/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx @@ -36,17 +36,17 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { Vis } from 'src/plugins/visualizations/public'; -import { SavedSearch } from 'src/plugins/discover/public'; +import { SavedObject } from 'src/plugins/saved_objects/public'; import { useKibana } from '../../../../kibana_react/public'; interface LinkedSearchProps { - savedSearch: SavedSearch; + savedSearch: SavedObject; eventEmitter: EventEmitter; } interface SidebarTitleProps { isLinkedSearch: boolean; - savedSearch?: SavedSearch; + savedSearch?: SavedObject; vis: Vis; eventEmitter: EventEmitter; } diff --git a/src/plugins/vis_default_editor/public/default_editor.tsx b/src/plugins/vis_default_editor/public/default_editor.tsx index 731358bdcbdec2..60b6ebab5ad8eb 100644 --- a/src/plugins/vis_default_editor/public/default_editor.tsx +++ b/src/plugins/vis_default_editor/public/default_editor.tsx @@ -59,7 +59,7 @@ function DefaultEditor({ embeddableHandler.render(visRef.current); setTimeout(() => { - eventEmitter.emit('apply'); + eventEmitter.emit('embeddableRendered'); }); return () => embeddableHandler.destroy(); @@ -102,6 +102,7 @@ function DefaultEditor({ initialWidth={editorInitialWidth} > get(col.aggConfig.type.getFormat(col.aggConfig), 'type.id') === 'number') + .filter((col) => get(col.aggConfig.toSerializedFieldFormat(), 'id') === 'number') .map(({ name }) => ({ value: name, text: name })), ], [aggs] diff --git a/src/plugins/vis_type_timelion/server/plugin.ts b/src/plugins/vis_type_timelion/server/plugin.ts index 435ec9027eef24..605c6be0a85df3 100644 --- a/src/plugins/vis_type_timelion/server/plugin.ts +++ b/src/plugins/vis_type_timelion/server/plugin.ts @@ -20,11 +20,9 @@ import { i18n } from '@kbn/i18n'; import { first } from 'rxjs/operators'; import { TypeOf } from '@kbn/config-schema'; -import { - CoreSetup, - PluginInitializerContext, - RecursiveReadonly, -} from '../../../../src/core/server'; +import { RecursiveReadonly } from '@kbn/utility-types'; + +import { CoreSetup, PluginInitializerContext } from '../../../../src/core/server'; import { deepFreeze } from '../../../../src/core/server'; import { configSchema } from '../config'; import loadFunctions from './lib/load_functions'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js b/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js index a96890d4d15029..300e70f3ae0c00 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js @@ -80,7 +80,7 @@ export class VisEditor extends Component { updateVisState = debounce(() => { this.props.vis.params = this.state.model; - this.props.eventEmitter.emit('updateVis'); + this.props.embeddableHandler.reload(); this.props.eventEmitter.emit('dirtyStateChange', { isDirty: false, }); @@ -187,6 +187,7 @@ export class VisEditor extends Component { autoApply={this.state.autoApply} model={model} embeddableHandler={this.props.embeddableHandler} + eventEmitter={this.props.eventEmitter} vis={this.props.vis} timeRange={this.props.timeRange} uiState={this.uiState} diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor_visualization.js b/src/plugins/vis_type_timeseries/public/application/components/vis_editor_visualization.js index 0ae1c86ae31175..23a9555da2452c 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_editor_visualization.js +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_editor_visualization.js @@ -73,6 +73,7 @@ class VisEditorVisualizationUI extends Component { this._handler = embeddableHandler; await this._handler.render(this._visEl.current); + this.props.eventEmitter.emit('embeddableRendered'); this._subscription = this._handler.handler.data$.subscribe((data) => { this.setPanelInterval(data.value.visData); @@ -279,6 +280,7 @@ VisEditorVisualizationUI.propTypes = { uiState: PropTypes.object, onToggleAutoApply: PropTypes.func, embeddableHandler: PropTypes.object, + eventEmitter: PropTypes.object, timeRange: PropTypes.object, dirty: PropTypes.bool, autoApply: PropTypes.bool, diff --git a/src/plugins/vis_type_timeseries/public/metrics_type.ts b/src/plugins/vis_type_timeseries/public/metrics_type.ts index c06f94efb3c493..649ee765cc6428 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/plugins/vis_type_timeseries/public/metrics_type.ts @@ -24,7 +24,6 @@ import { metricsRequestHandler } from './request_handler'; import { EditorController } from './application'; // @ts-ignore import { PANEL_TYPES } from '../common/panel_types'; -import { defaultFeedbackMessage } from '../../kibana_utils/public'; import { VisEditor } from './application/components/vis_editor_lazy'; export const metricsVisDefinition = { @@ -34,7 +33,6 @@ export const metricsVisDefinition = { defaultMessage: 'Build time-series using a visual pipeline interface', }), icon: 'visVisualBuilder', - feedbackMessage: defaultFeedbackMessage, visConfig: { defaults: { id: '61ca57f0-469d-11e7-af02-69e470af7417', diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts index a2146e493d4edf..0b1c6e6e204141 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts @@ -18,7 +18,7 @@ */ import { - APICaller, + LegacyAPICaller, FakeRequest, IUiSettingsClient, SavedObjectsClientContract, @@ -53,12 +53,12 @@ export type ReqFacade = FakeRequest & { }; export class AbstractSearchStrategy { - public getCallWithRequestInstance: (req: ReqFacade) => APICaller; + public getCallWithRequestInstance: (req: ReqFacade) => LegacyAPICaller; public getSearchRequest: (req: ReqFacade) => any; constructor( server: any, - callWithRequestFactory: (server: any, req: ReqFacade) => APICaller, + callWithRequestFactory: (server: any, req: ReqFacade) => LegacyAPICaller, SearchRequest: any ) { this.getCallWithRequestInstance = (req) => callWithRequestFactory(server, req); diff --git a/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts b/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts index 22e427bed24c3c..a5f095a4c4f3d1 100644 --- a/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts +++ b/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts @@ -17,7 +17,7 @@ * under the License. */ -import { APICaller, CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server'; +import { LegacyAPICaller, CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server'; import { UsageCollectionSetup } from '../../../usage_collection/server'; import { tsvbTelemetrySavedObjectType } from '../saved_objects'; @@ -49,7 +49,7 @@ export class ValidationTelemetryService implements Plugin({ type: 'tsvb-validation', isReady: () => this.kibanaIndex !== '', - fetch: async (callCluster: APICaller) => { + fetch: async (callCluster: LegacyAPICaller) => { try { const response = await callCluster('get', { index: this.kibanaIndex, diff --git a/src/plugins/vis_type_vega/public/vega_type.ts b/src/plugins/vis_type_vega/public/vega_type.ts index c864553c118b93..55ad134c053015 100644 --- a/src/plugins/vis_type_vega/public/vega_type.ts +++ b/src/plugins/vis_type_vega/public/vega_type.ts @@ -21,7 +21,6 @@ import { i18n } from '@kbn/i18n'; import { DefaultEditorSize } from '../../vis_default_editor/public'; import { VegaVisualizationDependencies } from './plugin'; import { VegaVisEditor } from './components'; -import { defaultFeedbackMessage } from '../../kibana_utils/public'; import { createVegaRequestHandler } from './vega_request_handler'; // @ts-ignore @@ -56,6 +55,5 @@ export const createVegaTypeDefinition = (dependencies: VegaVisualizationDependen showFilterBar: true, }, stage: 'experimental', - feedbackMessage: defaultFeedbackMessage, }; }; diff --git a/src/plugins/visualizations/public/index.ts b/src/plugins/visualizations/public/index.ts index 0bbf862216ed5b..2ac53c2c81acc9 100644 --- a/src/plugins/visualizations/public/index.ts +++ b/src/plugins/visualizations/public/index.ts @@ -51,4 +51,5 @@ export { VisSavedObject, VisResponseValue, } from './types'; +export { VisualizationListItem } from './vis_types/vis_type_alias_registry'; export { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants'; diff --git a/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts b/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts index eb00dce8aba2fd..8edf494ddc0ece 100644 --- a/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts +++ b/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts @@ -62,6 +62,7 @@ export const convertFromSerializedVis = (vis: SerializedVis): ISavedVis => { title: vis.title, description: vis.description, visState: { + title: vis.title, type: vis.type, aggs: vis.data.aggs, params: vis.params, diff --git a/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts b/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts index c6a25df7615a2b..d44fc2f4a75af0 100644 --- a/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts +++ b/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts @@ -56,7 +56,7 @@ export function createSavedVisLoader(services: SavedObjectKibanaServicesWithVisu source.icon = source.type.icon; source.image = source.type.image; source.typeTitle = source.type.title; - source.editUrl = `#/edit/${id}`; + source.editUrl = `/edit/${id}`; return source; }; diff --git a/src/plugins/visualizations/public/types.ts b/src/plugins/visualizations/public/types.ts index 3455d88b6ce9e1..daf275297fb822 100644 --- a/src/plugins/visualizations/public/types.ts +++ b/src/plugins/visualizations/public/types.ts @@ -35,6 +35,7 @@ export type VisualizationControllerConstructor = new ( ) => VisualizationController; export interface SavedVisState { + title: string; type: string; params: VisParams; aggs: AggConfigOptions[]; diff --git a/src/plugins/visualizations/public/vis.ts b/src/plugins/visualizations/public/vis.ts index aaab0566af65e6..e8ae48cdce1452 100644 --- a/src/plugins/visualizations/public/vis.ts +++ b/src/plugins/visualizations/public/vis.ts @@ -29,6 +29,7 @@ import { isFunction, defaults, cloneDeep } from 'lodash'; import { Assign } from '@kbn/utility-types'; +import { i18n } from '@kbn/i18n'; import { PersistedState } from './persisted_state'; import { getTypes, getAggs, getSearch, getSavedSearchLoader } from './services'; import { VisType } from './vis_types'; @@ -105,7 +106,13 @@ export class Vis { private getType(visType: string) { const type = getTypes().get(visType); if (!type) { - throw new Error(`Invalid type "${visType}"`); + const errorMessage = i18n.translate('visualizations.visualizationTypeInvalidMessage', { + defaultMessage: 'Invalid visualization type "{visType}"', + values: { + visType, + }, + }); + throw new Error(errorMessage); } return type; } @@ -150,7 +157,13 @@ export class Vis { const configStates = this.initializeDefaultsFromSchemas(aggs, this.type.schemas.all || []); if (!this.data.indexPattern) { if (aggs.length) { - throw new Error('trying to initialize aggs without index pattern'); + const errorMessage = i18n.translate( + 'visualizations.initializeWithoutIndexPatternErrorMessage', + { + defaultMessage: 'Trying to initialize aggs without index pattern', + } + ); + throw new Error(errorMessage); } return; } diff --git a/src/plugins/visualizations/public/vis_types/base_vis_type.ts b/src/plugins/visualizations/public/vis_types/base_vis_type.ts index 2464bb72d26957..44b76a52b34fef 100644 --- a/src/plugins/visualizations/public/vis_types/base_vis_type.ts +++ b/src/plugins/visualizations/public/vis_types/base_vis_type.ts @@ -27,7 +27,6 @@ export interface BaseVisTypeOptions { icon?: string; image?: string; stage?: 'experimental' | 'beta' | 'production'; - feedbackMessage?: string; options?: Record; visualization: VisualizationControllerConstructor; visConfig?: Record; @@ -48,7 +47,7 @@ export class BaseVisType { icon?: string; image?: string; stage: 'experimental' | 'beta' | 'production'; - feedbackMessage: string; + isExperimental: boolean; options: Record; visualization: VisualizationControllerConstructor; visConfig: Record; @@ -87,7 +86,7 @@ export class BaseVisType { this.editorConfig = _.defaultsDeep({}, opts.editorConfig, { collections: {} }); this.options = _.defaultsDeep({}, opts.options, defaultOptions); this.stage = opts.stage || 'production'; - this.feedbackMessage = opts.feedbackMessage || ''; + this.isExperimental = opts.stage === 'experimental'; this.hidden = opts.hidden || false; this.requestHandler = opts.requestHandler || 'courier'; this.responseHandler = opts.responseHandler || 'none'; @@ -97,10 +96,6 @@ export class BaseVisType { this.useCustomNoDataScreen = opts.useCustomNoDataScreen || false; } - shouldMarkAsExperimentalInUI() { - return this.stage === 'experimental'; - } - public get schemas() { if (this.editorConfig && this.editorConfig.schemas) { return this.editorConfig.schemas; diff --git a/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts b/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts index 73e3360004e5a7..bc80d549c81e6f 100644 --- a/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts +++ b/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts @@ -27,6 +27,7 @@ export interface VisualizationListItem { title: string; description?: string; typeTitle: string; + image?: string; } export interface VisualizationsAppExtension { diff --git a/src/plugins/visualize/kibana.json b/src/plugins/visualize/kibana.json index cda45f3acc102d..c27cfec24b332d 100644 --- a/src/plugins/visualize/kibana.json +++ b/src/plugins/visualize/kibana.json @@ -9,7 +9,6 @@ "navigation", "savedObjects", "visualizations", - "dashboard", "embeddable" ], "optionalPlugins": ["home", "share"] diff --git a/src/plugins/visualize/public/application/_app.scss b/src/plugins/visualize/public/application/_app.scss deleted file mode 100644 index 8a52ebf4cc0883..00000000000000 --- a/src/plugins/visualize/public/application/_app.scss +++ /dev/null @@ -1,5 +0,0 @@ -.visAppWrapper { - display: flex; - flex-direction: column; - flex-grow: 1; -} diff --git a/src/plugins/visualize/public/application/index.scss b/src/plugins/visualize/public/application/app.scss similarity index 67% rename from src/plugins/visualize/public/application/index.scss rename to src/plugins/visualize/public/application/app.scss index 620380a77ba46c..f7f68fbc2c3597 100644 --- a/src/plugins/visualize/public/application/index.scss +++ b/src/plugins/visualize/public/application/app.scss @@ -5,6 +5,8 @@ // visChart__legend--small // visChart__legend-isLoading -@import 'app'; -@import 'editor/index'; -@import 'listing/index'; +.visAppWrapper { + display: flex; + flex-direction: column; + flex-grow: 1; +} diff --git a/src/plugins/visualize/public/application/app.tsx b/src/plugins/visualize/public/application/app.tsx new file mode 100644 index 00000000000000..0e71d72a3d4c72 --- /dev/null +++ b/src/plugins/visualize/public/application/app.tsx @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import './app.scss'; +import React, { useEffect } from 'react'; +import { Route, Switch, useLocation } from 'react-router-dom'; + +import { syncQueryStateWithUrl } from '../../../data/public'; +import { useKibana } from '../../../kibana_react/public'; +import { VisualizeServices } from './types'; +import { VisualizeEditor, VisualizeListing, VisualizeNoMatch } from './components'; +import { VisualizeConstants } from './visualize_constants'; + +export const VisualizeApp = () => { + const { + services: { + data: { query }, + kbnUrlStateStorage, + }, + } = useKibana(); + const { pathname } = useLocation(); + + useEffect(() => { + // syncs `_g` portion of url with query services + const { stop } = syncQueryStateWithUrl(query, kbnUrlStateStorage); + + return () => stop(); + + // this effect should re-run when pathname is changed to preserve querystring part, + // so the global state is always preserved + }, [query, kbnUrlStateStorage, pathname]); + + return ( + + + + + + + + + + ); +}; diff --git a/src/plugins/visualize/public/application/application.ts b/src/plugins/visualize/public/application/application.ts deleted file mode 100644 index 60bb73d6de2ccb..00000000000000 --- a/src/plugins/visualize/public/application/application.ts +++ /dev/null @@ -1,111 +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 './index.scss'; - -import angular, { IModule } from 'angular'; - -// required for i18nIdDirective -import 'angular-sanitize'; -// required for ngRoute -import 'angular-route'; - -import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; - -import { AppMountContext } from 'kibana/public'; -import { NavigationPublicPluginStart as NavigationStart } from 'src/plugins/navigation/public'; -import { - configureAppAngularModule, - createTopNavDirective, - createTopNavHelper, -} from '../../../kibana_legacy/public'; - -// @ts-ignore -import { initVisualizeApp } from './legacy_app'; -import { VisualizeKibanaServices } from '../kibana_services'; - -let angularModuleInstance: IModule | null = null; - -export const renderApp = ( - element: HTMLElement, - appBasePath: string, - deps: VisualizeKibanaServices -) => { - if (!angularModuleInstance) { - angularModuleInstance = createLocalAngularModule(deps.core, deps.navigation); - // global routing stuff - configureAppAngularModule( - angularModuleInstance, - { core: deps.core, env: deps.pluginInitializerContext.env }, - true, - deps.scopedHistory - ); - 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('class', 'visAppWrapper'); - 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(); - createLocalTopNavModule(navigation); - - const visualizeAngularModule: IModule = angular.module(moduleName, [ - ...thirdPartyAngularDependencies, - 'app/visualize/I18n', - 'app/visualize/TopNav', - ]); - return visualizeAngularModule; -} - -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/core/utils/integration_tests/deep_freeze.test.ts b/src/plugins/visualize/public/application/components/experimental_vis_info.tsx similarity index 50% rename from src/core/utils/integration_tests/deep_freeze.test.ts rename to src/plugins/visualize/public/application/components/experimental_vis_info.tsx index f58e298fecfbff..51abb3ca530a4c 100644 --- a/src/core/utils/integration_tests/deep_freeze.test.ts +++ b/src/plugins/visualize/public/application/components/experimental_vis_info.tsx @@ -17,24 +17,33 @@ * under the License. */ -import { resolve } from 'path'; +import React, { memo } from 'react'; +import { EuiCallOut, EuiLink } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; -import execa from 'execa'; +export const InfoComponent = () => { + const title = ( + <> + {' '} + + GitHub + + {'.'} + + ); -const MINUTE = 60 * 1000; + return ( + + ); +}; -it( - 'types return values to prevent mutations in typescript', - async () => { - await expect( - execa('tsc', ['--noEmit'], { - cwd: resolve(__dirname, '__fixtures__/frozen_object_mutation'), - preferLocal: true, - }).catch((err) => err.stdout) - ).resolves.toMatchInlineSnapshot(` - "index.ts(28,12): error TS2540: Cannot assign to 'baz' because it is a read-only property. - index.ts(36,11): error TS2540: Cannot assign to 'bar' because it is a read-only property." - `); - }, - MINUTE -); +export const ExperimentalVisInfo = memo(InfoComponent); diff --git a/src/core/utils/integration_tests/__fixtures__/frozen_object_mutation/index.ts b/src/plugins/visualize/public/application/components/index.ts similarity index 72% rename from src/core/utils/integration_tests/__fixtures__/frozen_object_mutation/index.ts rename to src/plugins/visualize/public/application/components/index.ts index d4f001a914d34a..a3a7fde1d6569f 100644 --- a/src/core/utils/integration_tests/__fixtures__/frozen_object_mutation/index.ts +++ b/src/plugins/visualize/public/application/components/index.ts @@ -17,28 +17,6 @@ * under the License. */ -import { deepFreeze } from '../../../../utils/deep_freeze'; - -deepFreeze({ - foo: { - bar: { - baz: 1, - }, - }, -}).foo.bar.baz = 2; - -deepFreeze({ - foo: [ - { - bar: 1, - }, - ], -}).foo[0].bar = 2; - -deepFreeze({ - foo: [1], -}).foo[0] = 2; - -deepFreeze({ - foo: [1], -}).foo.push(2); +export { VisualizeListing } from './visualize_listing'; +export { VisualizeEditor } from './visualize_editor'; +export { VisualizeNoMatch } from './visualize_no_match'; diff --git a/src/plugins/visualize/public/application/editor/_editor.scss b/src/plugins/visualize/public/application/components/visualize_editor.scss similarity index 100% rename from src/plugins/visualize/public/application/editor/_editor.scss rename to src/plugins/visualize/public/application/components/visualize_editor.scss diff --git a/src/plugins/visualize/public/application/components/visualize_editor.tsx b/src/plugins/visualize/public/application/components/visualize_editor.tsx new file mode 100644 index 00000000000000..c571a5fb078bc5 --- /dev/null +++ b/src/plugins/visualize/public/application/components/visualize_editor.tsx @@ -0,0 +1,115 @@ +/* + * 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 './visualize_editor.scss'; +import React, { useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { EventEmitter } from 'events'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiScreenReaderOnly } from '@elastic/eui'; + +import { useKibana } from '../../../../kibana_react/public'; +import { + useChromeVisibility, + useSavedVisInstance, + useVisualizeAppState, + useEditorUpdates, + useLinkedSearchUpdates, +} from '../utils'; +import { VisualizeServices } from '../types'; +import { ExperimentalVisInfo } from './experimental_vis_info'; +import { VisualizeTopNav } from './visualize_top_nav'; + +export const VisualizeEditor = () => { + const { id: visualizationIdFromUrl } = useParams(); + const [originatingApp, setOriginatingApp] = useState(); + const { services } = useKibana(); + const [eventEmitter] = useState(new EventEmitter()); + const [hasUnsavedChanges, setHasUnsavedChanges] = useState(!visualizationIdFromUrl); + + const isChromeVisible = useChromeVisibility(services.chrome); + const { savedVisInstance, visEditorRef, visEditorController } = useSavedVisInstance( + services, + eventEmitter, + isChromeVisible, + visualizationIdFromUrl + ); + const { appState, hasUnappliedChanges } = useVisualizeAppState( + services, + eventEmitter, + savedVisInstance + ); + const { isEmbeddableRendered, currentAppState } = useEditorUpdates( + services, + eventEmitter, + setHasUnsavedChanges, + appState, + savedVisInstance, + visEditorController + ); + useLinkedSearchUpdates(services, eventEmitter, appState, savedVisInstance); + + useEffect(() => { + const { originatingApp: value } = + services.embeddable.getStateTransfer(services.scopedHistory).getIncomingEditorState() || {}; + setOriginatingApp(value); + }, [services]); + + useEffect(() => { + // clean up all registered listeners if any is left + return () => { + eventEmitter.removeAllListeners(); + }; + }, [eventEmitter]); + + return ( +
+ {savedVisInstance && appState && currentAppState && ( + + )} + {savedVisInstance?.vis?.type?.isExperimental && } + {savedVisInstance && ( + +

+ +

+
+ )} +
+
+ ); +}; diff --git a/src/plugins/visualize/public/application/listing/_listing.scss b/src/plugins/visualize/public/application/components/visualize_listing.scss similarity index 100% rename from src/plugins/visualize/public/application/listing/_listing.scss rename to src/plugins/visualize/public/application/components/visualize_listing.scss diff --git a/src/plugins/visualize/public/application/components/visualize_listing.tsx b/src/plugins/visualize/public/application/components/visualize_listing.tsx new file mode 100644 index 00000000000000..cbfbd6e0e3ab6b --- /dev/null +++ b/src/plugins/visualize/public/application/components/visualize_listing.tsx @@ -0,0 +1,154 @@ +/* + * 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 './visualize_listing.scss'; + +import React, { useCallback, useRef, useMemo, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { useUnmount, useMount } from 'react-use'; +import { useLocation } from 'react-router-dom'; + +import { useKibana, TableListView } from '../../../../kibana_react/public'; +import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../visualizations/public'; +import { VisualizeServices } from '../types'; +import { VisualizeConstants } from '../visualize_constants'; +import { getTableColumns, getNoItemsMessage } from '../utils'; + +export const VisualizeListing = () => { + const { + services: { + application, + chrome, + history, + savedVisualizations, + toastNotifications, + visualizations, + savedObjects, + savedObjectsPublic, + uiSettings, + visualizeCapabilities, + }, + } = useKibana(); + const { pathname } = useLocation(); + const closeNewVisModal = useRef(() => {}); + const listingLimit = savedObjectsPublic.settings.getListingLimit(); + + useEffect(() => { + if (pathname === '/new') { + // In case the user navigated to the page via the /visualize/new URL we start the dialog immediately + closeNewVisModal.current = visualizations.showNewVisModal({ + onClose: () => { + // In case the user came via a URL to this page, change the URL to the regular landing page URL after closing the modal + history.push(VisualizeConstants.LANDING_PAGE_PATH); + }, + }); + } else { + // close modal window if exists + closeNewVisModal.current(); + } + }, [history, pathname, visualizations]); + + useMount(() => { + chrome.setBreadcrumbs([ + { + text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', { + defaultMessage: 'Visualize', + }), + }, + ]); + chrome.docTitle.change( + i18n.translate('visualize.listingPageTitle', { defaultMessage: 'Visualize' }) + ); + }); + useUnmount(() => closeNewVisModal.current()); + + const createNewVis = useCallback(() => { + closeNewVisModal.current = visualizations.showNewVisModal(); + }, [visualizations]); + + const editItem = useCallback( + ({ editUrl, editApp }) => { + if (editApp) { + application.navigateToApp(editApp, { path: editUrl }); + return; + } + // for visualizations the edit and view URLs are the same + history.push(editUrl); + }, + [application, history] + ); + + const noItemsFragment = useMemo(() => getNoItemsMessage(createNewVis), [createNewVis]); + const tableColumns = useMemo(() => getTableColumns(application, history), [application, history]); + + const fetchItems = useCallback( + (filter) => { + const isLabsEnabled = uiSettings.get(VISUALIZE_ENABLE_LABS_SETTING); + return savedVisualizations + .findListItems(filter, listingLimit) + .then(({ total, hits }: { total: number; hits: object[] }) => ({ + total, + hits: hits.filter((result: any) => isLabsEnabled || result.type.stage !== 'experimental'), + })); + }, + [listingLimit, savedVisualizations, uiSettings] + ); + + const deleteItems = useCallback( + async (selectedItems: object[]) => { + await Promise.all( + selectedItems.map((item: any) => savedObjects.client.delete(item.savedObjectType, item.id)) + ).catch((error) => { + toastNotifications.addError(error, { + title: i18n.translate('visualize.visualizeListingDeleteErrorTitle', { + defaultMessage: 'Error deleting visualization', + }), + }); + }); + }, + [savedObjects.client, toastNotifications] + ); + + return ( + + ); +}; diff --git a/src/plugins/visualize/public/application/components/visualize_no_match.tsx b/src/plugins/visualize/public/application/components/visualize_no_match.tsx new file mode 100644 index 00000000000000..7776c5e8ce4866 --- /dev/null +++ b/src/plugins/visualize/public/application/components/visualize_no_match.tsx @@ -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 React, { useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCallOut, EuiLink } from '@elastic/eui'; + +import { useKibana, toMountPoint } from '../../../../kibana_react/public'; +import { VisualizeServices } from '../types'; +import { VisualizeConstants } from '../visualize_constants'; + +let bannerId: string; + +export const VisualizeNoMatch = () => { + const { services } = useKibana(); + + useEffect(() => { + services.restorePreviousUrl(); + + const { navigated } = services.kibanaLegacy.navigateToLegacyKibanaUrl( + services.history.location.pathname + ); + + if (!navigated) { + const bannerMessage = i18n.translate('visualize.noMatchRoute.bannerTitleText', { + defaultMessage: 'Page not found', + }); + + bannerId = services.overlays.banners.replace( + bannerId, + toMountPoint( + +

+ + {services.history.location.pathname} + + ), + }} + /> +

+
+ ) + ); + + // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around + setTimeout(() => { + services.overlays.banners.remove(bannerId); + }, 15000); + + services.history.replace(VisualizeConstants.LANDING_PAGE_PATH); + } + }, [services]); + + return null; +}; diff --git a/src/plugins/visualize/public/application/components/visualize_top_nav.tsx b/src/plugins/visualize/public/application/components/visualize_top_nav.tsx new file mode 100644 index 00000000000000..2e7dba46487ad0 --- /dev/null +++ b/src/plugins/visualize/public/application/components/visualize_top_nav.tsx @@ -0,0 +1,178 @@ +/* + * 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, { memo, useCallback, useMemo, useState, useEffect } from 'react'; +import { isEqual } from 'lodash'; + +import { OverlayRef } from 'kibana/public'; +import { Query } from 'src/plugins/data/public'; +import { useKibana } from '../../../../kibana_react/public'; +import { + VisualizeServices, + VisualizeAppState, + VisualizeAppStateContainer, + SavedVisInstance, +} from '../types'; +import { APP_NAME } from '../visualize_constants'; +import { getTopNavConfig } from '../utils'; + +interface VisualizeTopNavProps { + currentAppState: VisualizeAppState; + isChromeVisible?: boolean; + isEmbeddableRendered: boolean; + hasUnsavedChanges: boolean; + setHasUnsavedChanges: (value: boolean) => void; + hasUnappliedChanges: boolean; + originatingApp?: string; + savedVisInstance: SavedVisInstance; + stateContainer: VisualizeAppStateContainer; + visualizationIdFromUrl?: string; +} + +const TopNav = ({ + currentAppState, + isChromeVisible, + isEmbeddableRendered, + hasUnsavedChanges, + setHasUnsavedChanges, + hasUnappliedChanges, + originatingApp, + savedVisInstance, + stateContainer, + visualizationIdFromUrl, +}: VisualizeTopNavProps) => { + const { services } = useKibana(); + const { TopNavMenu } = services.navigation.ui; + const { embeddableHandler, vis } = savedVisInstance; + const [inspectorSession, setInspectorSession] = useState(); + const openInspector = useCallback(() => { + const session = embeddableHandler.openInspector(); + setInspectorSession(session); + }, [embeddableHandler]); + + const updateQuery = useCallback( + ({ query }: { query?: Query }) => { + if (!isEqual(currentAppState.query, query)) { + stateContainer.transitions.set('query', query || currentAppState.query); + } else { + savedVisInstance.embeddableHandler.reload(); + } + }, + [currentAppState.query, savedVisInstance.embeddableHandler, stateContainer.transitions] + ); + + const config = useMemo(() => { + if (isEmbeddableRendered) { + return getTopNavConfig( + { + hasUnsavedChanges, + setHasUnsavedChanges, + hasUnappliedChanges, + openInspector, + originatingApp, + savedVisInstance, + stateContainer, + visualizationIdFromUrl, + }, + services + ); + } + }, [ + isEmbeddableRendered, + hasUnsavedChanges, + setHasUnsavedChanges, + hasUnappliedChanges, + openInspector, + originatingApp, + savedVisInstance, + stateContainer, + visualizationIdFromUrl, + services, + ]); + const [indexPattern, setIndexPattern] = useState(vis.data.indexPattern); + const showDatePicker = () => { + // tsvb loads without an indexPattern initially (TODO investigate). + // hide timefilter only if timeFieldName is explicitly undefined. + const hasTimeField = vis.data.indexPattern ? !!vis.data.indexPattern.timeFieldName : true; + return vis.type.options.showTimePicker && hasTimeField; + }; + const showFilterBar = vis.type.options.showFilterBar; + const showQueryInput = vis.type.requiresSearch && vis.type.options.showQueryBar; + + useEffect(() => { + return () => { + if (inspectorSession) { + // Close the inspector if this scope is destroyed (e.g. because the user navigates away). + inspectorSession.close(); + } + }; + }, [inspectorSession]); + + useEffect(() => { + if (!vis.data.indexPattern) { + services.data.indexPatterns.getDefault().then((index) => { + if (index) { + setIndexPattern(index); + } + }); + } + }, [services.data.indexPatterns, vis.data.indexPattern]); + + return isChromeVisible ? ( + /** + * Most visualizations have all search bar components enabled. + * Some visualizations have fewer options, but all visualizations have the search bar. + * That's is why the showSearchBar prop is set. + * All visualizations also have the timepicker\autorefresh component, + * it is enabled by default in the TopNavMenu component. + */ + + ) : showFilterBar ? ( + /** + * The top nav is hidden in embed mode, but the filter bar must still be present so + * we show the filter bar on its own here if the chrome is not visible. + */ + + ) : null; +}; + +export const VisualizeTopNav = memo(TopNav); diff --git a/src/plugins/visualize/public/application/editor/_index.scss b/src/plugins/visualize/public/application/editor/_index.scss deleted file mode 100644 index 9d3ca4b5399472..00000000000000 --- a/src/plugins/visualize/public/application/editor/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'editor'; diff --git a/src/plugins/visualize/public/application/editor/editor.html b/src/plugins/visualize/public/application/editor/editor.html deleted file mode 100644 index 3c3455fb34f18c..00000000000000 --- a/src/plugins/visualize/public/application/editor/editor.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - -
-
-

-
-
- - - -

-

- - -
diff --git a/src/plugins/visualize/public/application/editor/editor.js b/src/plugins/visualize/public/application/editor/editor.js deleted file mode 100644 index d7c7828c58f23f..00000000000000 --- a/src/plugins/visualize/public/application/editor/editor.js +++ /dev/null @@ -1,763 +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 angular from 'angular'; -import _ from 'lodash'; -import { Subscription } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { i18n } from '@kbn/i18n'; -import { EventEmitter } from 'events'; - -import React from 'react'; -import { makeStateful, useVisualizeAppState } from './lib'; -import { VisualizeConstants } from '../visualize_constants'; -import { getEditBreadcrumbs } from '../breadcrumbs'; - -import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; -import { unhashUrl } from '../../../../kibana_utils/public'; -import { MarkdownSimple, toMountPoint } from '../../../../kibana_react/public'; -import { - addFatalError, - subscribeWithScope, - migrateLegacyQuery, -} from '../../../../kibana_legacy/public'; -import { showSaveModal, SavedObjectSaveModalOrigin } from '../../../../saved_objects/public'; -import { - esFilters, - connectToQueryState, - syncQueryStateWithUrl, - UI_SETTINGS, -} from '../../../../data/public'; - -import { initVisEditorDirective } from './visualization_editor'; -import { initVisualizationDirective } from './visualization'; - -import { getServices } from '../../kibana_services'; -import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../visualizations/public'; - -export function initEditorDirective(app, deps) { - app.directive('visualizeApp', function () { - return { - restrict: 'E', - controllerAs: 'visualizeApp', - controller: VisualizeAppController, - }; - }); - - initVisEditorDirective(app, deps); - initVisualizationDirective(app, deps); -} - -function VisualizeAppController($scope, $route, $injector, $timeout, kbnUrlStateStorage, history) { - const { - localStorage, - visualizeCapabilities, - share, - data: { query: queryService, indexPatterns }, - toastNotifications, - chrome, - core: { docLinks, fatalErrors, uiSettings, application }, - I18nContext, - setActiveUrl, - visualizations, - embeddable, - scopedHistory, - } = getServices(); - - const { - filterManager, - timefilter: { timefilter }, - } = queryService; - - // starts syncing `_g` portion of url with query services - const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl( - queryService, - kbnUrlStateStorage - ); - - // Retrieve the resolved SavedVis instance. - const { vis, savedVis, savedSearch, embeddableHandler } = $route.current.locals.resolved; - $scope.eventEmitter = new EventEmitter(); - 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. - $scope.eventEmitter.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 searchSource = vis.data.searchSource; - - $scope.vis = vis; - $scope.savedSearch = savedSearch; - - const $appStatus = { - dirty: !savedVis.id, - }; - - const defaultQuery = { - query: '', - language: - localStorage.get('kibana.userQueryLanguage') || - uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE), - }; - - const { originatingApp } = - embeddable.getStateTransfer(scopedHistory()).getIncomingEditorState() || {}; - $scope.getOriginatingApp = () => originatingApp; - - const visStateToEditorState = () => { - const savedVisState = visualizations.convertFromSerializedVis(vis.serialize()); - return { - uiState: vis.uiState.toJSON(), - query: vis.data.searchSource.getOwnField('query') || defaultQuery, - filters: vis.data.searchSource.getOwnField('filter') || [], - vis: { ...savedVisState.visState, title: vis.title }, - linked: !!savedVis.savedSearchId, - }; - }; - - const stateDefaults = visStateToEditorState(); - - const { stateContainer, stopStateSync } = useVisualizeAppState({ - stateDefaults, - kbnUrlStateStorage, - }); - - $scope.eventEmitter.on('dirtyStateChange', ({ isDirty }) => { - if (!isDirty) { - stateContainer.transitions.updateVisState(visStateToEditorState().vis); - } - $timeout(() => { - $scope.dirty = isDirty; - }); - }); - - $scope.eventEmitter.on('updateVis', () => { - embeddableHandler.reload(); - }); - - $scope.embeddableHandler = embeddableHandler; - - $scope.topNavMenu = [ - ...($scope.getOriginatingApp() && savedVis.id - ? [ - { - id: 'saveAndReturn', - label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { - defaultMessage: 'Save and return', - }), - emphasize: true, - iconType: 'check', - description: i18n.translate( - 'visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', - { - defaultMessage: 'Finish editing visualization and return to the last app', - } - ), - testId: 'visualizesaveAndReturnButton', - disableButton() { - return Boolean($scope.dirty); - }, - tooltip() { - if ($scope.dirty) { - return i18n.translate( - 'visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip', - { - defaultMessage: 'Apply or Discard your changes before finishing', - } - ); - } - }, - run: async () => { - const saveOptions = { - confirmOverwrite: false, - returnToOrigin: true, - }; - return doSave(saveOptions); - }, - }, - ] - : []), - ...(visualizeCapabilities.save - ? [ - { - id: 'save', - label: - savedVis.id && $scope.getOriginatingApp() - ? i18n.translate('visualize.topNavMenu.saveVisualizationAsButtonLabel', { - defaultMessage: 'save as', - }) - : i18n.translate('visualize.topNavMenu.saveVisualizationButtonLabel', { - defaultMessage: 'save', - }), - emphasize: !savedVis.id || !$scope.getOriginatingApp(), - description: i18n.translate('visualize.topNavMenu.saveVisualizationButtonAriaLabel', { - defaultMessage: 'Save Visualization', - }), - testId: 'visualizeSaveButton', - disableButton() { - return Boolean($scope.dirty); - }, - tooltip() { - if ($scope.dirty) { - return i18n.translate( - 'visualize.topNavMenu.saveVisualizationDisabledButtonTooltip', - { - defaultMessage: 'Apply or Discard your changes before saving', - } - ); - } - }, - run: async () => { - const onSave = ({ - newTitle, - newCopyOnSave, - isTitleDuplicateConfirmed, - onTitleDuplicate, - newDescription, - returnToOrigin, - }) => { - const currentTitle = savedVis.title; - savedVis.title = newTitle; - savedVis.copyOnSave = newCopyOnSave; - savedVis.description = newDescription; - const saveOptions = { - confirmOverwrite: false, - isTitleDuplicateConfirmed, - onTitleDuplicate, - returnToOrigin, - }; - return doSave(saveOptions).then((response) => { - // If the save wasn't successful, put the original values back. - if (!response.id || response.error) { - savedVis.title = currentTitle; - } - return response; - }); - }; - - const saveModal = ( - {}} - originatingApp={$scope.getOriginatingApp()} - /> - ); - showSaveModal(saveModal, I18nContext); - }, - }, - ] - : []), - { - id: 'share', - label: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', { - defaultMessage: 'share', - }), - description: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', { - defaultMessage: 'Share Visualization', - }), - testId: 'shareTopNavButton', - run: (anchorElement) => { - const hasUnappliedChanges = $scope.dirty; - const hasUnsavedChanges = $appStatus.dirty; - share.toggleShareContextMenu({ - anchorElement, - allowEmbed: true, - allowShortUrl: visualizeCapabilities.createShortUrl, - shareableUrl: unhashUrl(window.location.href), - objectId: savedVis.id, - objectType: 'visualization', - sharingData: { - title: savedVis.title, - }, - isDirty: hasUnappliedChanges || hasUnsavedChanges, - }); - }, - // disable the Share button if no action specified - disableButton: !share, - }, - { - id: 'inspector', - label: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', { - defaultMessage: 'inspect', - }), - description: i18n.translate('visualize.topNavMenu.openInspectorButtonAriaLabel', { - defaultMessage: 'Open Inspector for visualization', - }), - testId: 'openInspectorButton', - disableButton() { - return !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(); - }, - run() { - const inspectorSession = embeddableHandler.openInspector(); - - if (inspectorSession) { - // Close the inspector if this scope is destroyed (e.g. because the user navigates away). - const removeWatch = $scope.$on('$destroy', () => inspectorSession.close()); - // Remove that watch in case the user closes the inspector session herself. - inspectorSession.onClose.finally(removeWatch); - } - }, - tooltip() { - if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) { - return i18n.translate('visualize.topNavMenu.openInspectorDisabledButtonTooltip', { - defaultMessage: `This visualization doesn't support any inspectors.`, - }); - } - }, - }, - ]; - - if (savedVis.id) { - chrome.docTitle.change(savedVis.title); - } - - // sync initial app filters from state to filterManager - filterManager.setAppFilters(_.cloneDeep(stateContainer.getState().filters)); - // setup syncing of app filters between appState and filterManager - const stopSyncingAppFilters = connectToQueryState( - queryService, - { - set: ({ filters }) => stateContainer.transitions.set('filters', filters), - get: () => ({ filters: stateContainer.getState().filters }), - state$: stateContainer.state$.pipe(map((state) => ({ filters: state.filters }))), - }, - { - filters: esFilters.FilterStateStore.APP_STATE, - } - ); - - const stopAllSyncing = () => { - stopStateSync(); - stopSyncingQueryServiceStateWithUrl(); - stopSyncingAppFilters(); - }; - - // The savedVis is pulled from elasticsearch, but the appState is pulled from the url, with the - // defaults applied. If the url was from a previous session which included modifications to the - // appState then they won't be equal. - if (!_.isEqual(stateContainer.getState().vis, stateDefaults.vis)) { - try { - const { aggs, ...visState } = stateContainer.getState().vis; - vis.setState({ ...visState, data: { aggs } }); - } catch (error) { - // stop syncing url updtes with the state to prevent extra syncing - stopAllSyncing(); - - toastNotifications.addWarning({ - title: i18n.translate('visualize.visualizationTypeInvalidNotificationMessage', { - defaultMessage: 'Invalid visualization type', - }), - text: toMountPoint({error.message}), - }); - - history.replace(`${VisualizeConstants.LANDING_PAGE_PATH}?notFound=visualization`); - - // prevent further controller execution - return; - } - } - - $scope.filters = filterManager.getFilters(); - - $scope.onFiltersUpdated = (filters) => { - // The filters will automatically be set when the filterManager emits an update event (see below) - filterManager.setFilters(filters); - }; - - $scope.showSaveQuery = visualizeCapabilities.saveQuery; - - $scope.$watch( - () => visualizeCapabilities.saveQuery, - (newCapability) => { - $scope.showSaveQuery = newCapability; - } - ); - - const updateSavedQueryFromUrl = (savedQueryId) => { - if (!savedQueryId) { - delete $scope.savedQuery; - - return; - } - - if ($scope.savedQuery && $scope.savedQuery.id === savedQueryId) { - return; - } - - queryService.savedQueries.getSavedQuery(savedQueryId).then((savedQuery) => { - $scope.$evalAsync(() => { - $scope.updateSavedQuery(savedQuery); - }); - }); - }; - - function init() { - if (vis.data.indexPattern) { - $scope.indexPattern = vis.data.indexPattern; - } else { - indexPatterns.getDefault().then((defaultIndexPattern) => { - $scope.indexPattern = defaultIndexPattern; - }); - } - - const initialState = stateContainer.getState(); - - const handleLinkedSearch = (linked) => { - if (linked && !savedVis.savedSearchId && savedSearch) { - savedVis.savedSearchId = savedSearch.id; - vis.data.savedSearchId = savedSearch.id; - searchSource.setParent(savedSearch.searchSource); - } else if (!linked && savedVis.savedSearchId) { - delete savedVis.savedSearchId; - delete vis.data.savedSearchId; - } - }; - - // Create a PersistedState instance for uiState. - const { persistedState, unsubscribePersisted, persistOnChange } = makeStateful( - 'uiState', - stateContainer - ); - vis.uiState = persistedState; - vis.uiState.on('reload', embeddableHandler.reload); - $scope.uiState = persistedState; - $scope.savedVis = savedVis; - $scope.query = initialState.query; - $scope.searchSource = searchSource; - $scope.refreshInterval = timefilter.getRefreshInterval(); - handleLinkedSearch(initialState.linked); - - $scope.showFilterBar = () => { - return vis.type.options.showFilterBar; - }; - - $scope.showQueryInput = () => { - return vis.type.requiresSearch && vis.type.options.showQueryBar; - }; - - $scope.showQueryBarTimePicker = () => { - // tsvb loads without an indexPattern initially (TODO investigate). - // hide timefilter only if timeFieldName is explicitly undefined. - const hasTimeField = vis.data.indexPattern ? !!vis.data.indexPattern.timeFieldName : true; - return vis.type.options.showTimePicker && hasTimeField; - }; - - $scope.timeRange = timefilter.getTime(); - - const unsubscribeStateUpdates = stateContainer.subscribe((state) => { - const newQuery = migrateLegacyQuery(state.query); - if (!_.isEqual(state.query, newQuery)) { - stateContainer.transitions.set('query', newQuery); - } - persistOnChange(state); - updateSavedQueryFromUrl(state.savedQuery); - - // if the browser history was changed manually we need to reflect changes in the editor - if ( - !_.isEqual( - { - ...visualizations.convertFromSerializedVis(vis.serialize()).visState, - title: vis.title, - }, - state.vis - ) - ) { - const { aggs, ...visState } = state.vis; - vis.setState({ - ...visState, - data: { - aggs, - }, - }); - embeddableHandler.reload(); - $scope.eventEmitter.emit('updateEditor'); - } - - $appStatus.dirty = true; - $scope.fetch(); - }); - - const updateTimeRange = () => { - $scope.timeRange = timefilter.getTime(); - $scope.$broadcast('render'); - }; - - // update the query if savedQuery is stored - updateSavedQueryFromUrl(initialState.savedQuery); - - const subscriptions = new Subscription(); - - subscriptions.add( - subscribeWithScope( - $scope, - timefilter.getRefreshIntervalUpdate$(), - { - next: () => { - $scope.refreshInterval = timefilter.getRefreshInterval(); - }, - }, - (error) => addFatalError(fatalErrors, error) - ) - ); - subscriptions.add( - subscribeWithScope( - $scope, - timefilter.getTimeUpdate$(), - { - next: updateTimeRange, - }, - (error) => addFatalError(fatalErrors, error) - ) - ); - - subscriptions.add( - chrome.getIsVisible$().subscribe((isVisible) => { - $scope.$evalAsync(() => { - $scope.isVisible = isVisible; - }); - }) - ); - - // update the searchSource when query updates - $scope.fetch = function () { - const { query, linked, filters } = stateContainer.getState(); - $scope.query = query; - handleLinkedSearch(linked); - vis.data.searchSource.setField('query', query); - vis.data.searchSource.setField('filter', filters); - $scope.$broadcast('render'); - }; - - // update the searchSource when filters update - subscriptions.add( - subscribeWithScope( - $scope, - filterManager.getUpdates$(), - { - next: () => { - $scope.filters = filterManager.getFilters(); - }, - }, - (error) => addFatalError(fatalErrors, error) - ) - ); - subscriptions.add( - subscribeWithScope( - $scope, - filterManager.getFetches$(), - { - next: $scope.fetch, - }, - (error) => addFatalError(fatalErrors, error) - ) - ); - - $scope.$on('$destroy', () => { - if ($scope._handler) { - $scope._handler.destroy(); - } - savedVis.destroy(); - subscriptions.unsubscribe(); - $scope.eventEmitter.off('apply', _applyVis); - - unsubscribePersisted(); - vis.uiState.off('reload', embeddableHandler.reload); - unsubscribeStateUpdates(); - - stopAllSyncing(); - }); - - $timeout(() => { - $scope.$broadcast('render'); - }); - } - - $scope.updateQueryAndFetch = function ({ query, dateRange }) { - const isUpdate = - (query && !_.isEqual(query, stateContainer.getState().query)) || - (dateRange && !_.isEqual(dateRange, $scope.timeRange)); - - stateContainer.transitions.set('query', query); - timefilter.setTime(dateRange); - - // If nothing has changed, trigger the fetch manually, otherwise it will happen as a result of the changes - if (!isUpdate) { - embeddableHandler.reload(); - } - }; - - $scope.onRefreshChange = function ({ isPaused, refreshInterval }) { - timefilter.setRefreshInterval({ - pause: isPaused, - value: refreshInterval ? refreshInterval : $scope.refreshInterval.value, - }); - }; - - $scope.onClearSavedQuery = () => { - delete $scope.savedQuery; - stateContainer.transitions.removeSavedQuery(defaultQuery); - filterManager.setFilters(filterManager.getGlobalFilters()); - }; - - const updateStateFromSavedQuery = (savedQuery) => { - stateContainer.transitions.updateFromSavedQuery(savedQuery); - - const savedQueryFilters = savedQuery.attributes.filters || []; - const globalFilters = filterManager.getGlobalFilters(); - filterManager.setFilters([...globalFilters, ...savedQueryFilters]); - - if (savedQuery.attributes.timefilter) { - timefilter.setTime({ - from: savedQuery.attributes.timefilter.from, - to: savedQuery.attributes.timefilter.to, - }); - if (savedQuery.attributes.timefilter.refreshInterval) { - timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval); - } - } - }; - - $scope.updateSavedQuery = (savedQuery) => { - $scope.savedQuery = savedQuery; - updateStateFromSavedQuery(savedQuery); - }; - - /** - * Called when the user clicks "Save" button. - */ - function doSave(saveOptions) { - // vis.title was not bound and it's needed to reflect title into visState - const newlyCreated = !Boolean(savedVis.id) || savedVis.copyOnSave; - stateContainer.transitions.setVis({ - title: savedVis.title, - type: savedVis.type || stateContainer.getState().vis.type, - }); - savedVis.searchSourceFields = searchSource.getSerializedFields(); - savedVis.visState = stateContainer.getState().vis; - savedVis.uiStateJSON = angular.toJson($scope.uiState.toJSON()); - $appStatus.dirty = false; - - return savedVis.save(saveOptions).then( - function (id) { - $scope.$evalAsync(() => { - if (id) { - toastNotifications.addSuccess({ - title: i18n.translate( - 'visualize.topNavMenu.saveVisualization.successNotificationText', - { - defaultMessage: `Saved '{visTitle}'`, - values: { - visTitle: savedVis.title, - }, - } - ), - 'data-test-subj': 'saveVisualizationSuccess', - }); - - if ($scope.getOriginatingApp() && saveOptions.returnToOrigin) { - const appPath = `${VisualizeConstants.EDIT_PATH}/${encodeURIComponent(savedVis.id)}`; - - // Manually insert a new url so the back button will open the saved visualization. - history.replace(appPath); - setActiveUrl(appPath); - if (newlyCreated && embeddable) { - embeddable - .getStateTransfer() - .navigateToWithEmbeddablePackage($scope.getOriginatingApp(), { - state: { id: savedVis.id, type: VISUALIZE_EMBEDDABLE_TYPE }, - }); - } else { - application.navigateToApp($scope.getOriginatingApp()); - } - } else if (savedVis.id === $route.current.params.id) { - chrome.docTitle.change(savedVis.lastSavedTitle); - chrome.setBreadcrumbs($injector.invoke(getEditBreadcrumbs)); - savedVis.vis.title = savedVis.title; - savedVis.vis.description = savedVis.description; - } else { - history.replace({ - ...history.location, - pathname: `${VisualizeConstants.EDIT_PATH}/${savedVis.id}`, - }); - } - } - }); - return { id }; - }, - (error) => { - // eslint-disable-next-line - console.error(error); - toastNotifications.addDanger({ - title: i18n.translate('visualize.topNavMenu.saveVisualization.failureNotificationText', { - defaultMessage: `Error on saving '{visTitle}'`, - values: { - visTitle: savedVis.title, - }, - }), - text: error.message, - 'data-test-subj': 'saveVisualizationError', - }); - return { error }; - } - ); - } - - const unlinkFromSavedSearch = () => { - const searchSourceParent = savedSearch.searchSource; - const searchSourceGrandparent = searchSourceParent.getParent(); - const currentIndex = searchSourceParent.getField('index'); - - searchSource.setField('index', currentIndex); - searchSource.setParent(searchSourceGrandparent); - - stateContainer.transitions.unlinkSavedSearch({ - query: searchSourceParent.getField('query'), - parentFilters: searchSourceParent.getOwnField('filter'), - }); - - toastNotifications.addSuccess( - i18n.translate('visualize.linkedToSearch.unlinkSuccessNotificationText', { - defaultMessage: `Unlinked from saved search '{searchTitle}'`, - values: { - searchTitle: savedSearch.title, - }, - }) - ); - }; - - $scope.getAdditionalMessage = () => { - return ( - '' + - i18n.translate('visualize.experimentalVisInfoText', { - defaultMessage: 'This visualization is marked as experimental.', - }) + - ' ' + - vis.type.feedbackMessage - ); - }; - - $scope.eventEmitter.on('unlinkFromSavedSearch', unlinkFromSavedSearch); - - addHelpMenuToAppChrome(chrome, docLinks); - - init(); -} diff --git a/src/plugins/visualize/public/application/editor/lib/make_stateful.ts b/src/plugins/visualize/public/application/editor/lib/make_stateful.ts deleted file mode 100644 index c7163f9b7705d4..00000000000000 --- a/src/plugins/visualize/public/application/editor/lib/make_stateful.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 { PersistedState } from '../../../../../visualizations/public'; -import { ReduxLikeStateContainer } from '../../../../../kibana_utils/public'; -import { VisualizeAppState, VisualizeAppStateTransitions } from '../../types'; - -/** - * @returns Create a PersistedState instance, initialize state changes subscriber/unsubscriber - */ -export function makeStateful( - prop: keyof VisualizeAppState, - stateContainer: ReduxLikeStateContainer -) { - // set up the persistedState state - const persistedState = new PersistedState(); - - // update the appState when the stateful instance changes - const updateOnChange = function () { - stateContainer.transitions.set(prop, persistedState.getChanges()); - }; - - const handlerOnChange = (method: 'on' | 'off') => - persistedState[method]('change', updateOnChange); - - handlerOnChange('on'); - const unsubscribePersisted = () => handlerOnChange('off'); - - // update the stateful object when the app state changes - const persistOnChange = function (state: VisualizeAppState) { - if (state[prop]) { - persistedState.set(state[prop]); - } - }; - - const appState = stateContainer.getState(); - - // if the thing we're making stateful has an appState value, write to persisted state - if (appState[prop]) persistedState.setSilent(appState[prop]); - - return { persistedState, unsubscribePersisted, persistOnChange }; -} diff --git a/src/plugins/visualize/public/application/editor/visualization.js b/src/plugins/visualize/public/application/editor/visualization.js deleted file mode 100644 index 26f61f3f0a2c2b..00000000000000 --- a/src/plugins/visualize/public/application/editor/visualization.js +++ /dev/null @@ -1,61 +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. - */ - -export function initVisualizationDirective(app) { - app.directive('visualizationEmbedded', function ($timeout) { - return { - restrict: 'E', - scope: { - embeddableHandler: '=', - uiState: '=?', - timeRange: '=', - filters: '=', - query: '=', - appState: '=', - }, - link: function ($scope, element) { - $scope.renderFunction = async () => { - if (!$scope.rendered) { - $scope.embeddableHandler.render(element[0]); - $scope.rendered = true; - } - - $scope.embeddableHandler.updateInput({ - timeRange: $scope.timeRange, - filters: $scope.filters || [], - query: $scope.query, - }); - }; - - $scope.$on('render', (event) => { - event.preventDefault(); - $timeout(() => { - $scope.renderFunction(); - }); - }); - - $scope.$on('$destroy', () => { - if ($scope.embeddableHandler) { - $scope.embeddableHandler.destroy(); - } - }); - }, - }; - }); -} diff --git a/src/plugins/visualize/public/application/editor/visualization_editor.js b/src/plugins/visualize/public/application/editor/visualization_editor.js deleted file mode 100644 index 4963d9bc5ed72e..00000000000000 --- a/src/plugins/visualize/public/application/editor/visualization_editor.js +++ /dev/null @@ -1,71 +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 { DefaultEditorController } from '../../../../vis_default_editor/public'; - -export function initVisEditorDirective(app, deps) { - app.directive('visualizationEditor', function ($timeout) { - return { - restrict: 'E', - scope: { - vis: '=', - uiState: '=?', - timeRange: '=', - filters: '=', - query: '=', - savedSearch: '=', - embeddableHandler: '=', - eventEmitter: '=', - }, - link: function ($scope, element) { - const Editor = $scope.vis.type.editor || DefaultEditorController; - const editor = new Editor( - element[0], - $scope.vis, - $scope.eventEmitter, - $scope.embeddableHandler - ); - - $scope.renderFunction = () => { - editor.render({ - core: deps.core, - data: deps.data, - uiState: $scope.uiState, - timeRange: $scope.timeRange, - filters: $scope.filters, - query: $scope.query, - linked: !!$scope.vis.data.savedSearchId, - savedSearch: $scope.savedSearch, - }); - }; - - $scope.$on('render', (event) => { - event.preventDefault(); - $timeout(() => { - $scope.renderFunction(); - }); - }); - - $scope.$on('$destroy', () => { - editor.destroy(); - }); - }, - }; - }); -} diff --git a/src/plugins/visualize/public/application/index.tsx b/src/plugins/visualize/public/application/index.tsx new file mode 100644 index 00000000000000..4bec244e6efc94 --- /dev/null +++ b/src/plugins/visualize/public/application/index.tsx @@ -0,0 +1,51 @@ +/* + * 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 ReactDOM from 'react-dom'; +import { Router } from 'react-router-dom'; + +import { AppMountParameters } from 'kibana/public'; +import { KibanaContextProvider } from '../../../kibana_react/public'; +import { VisualizeApp } from './app'; +import { VisualizeServices } from './types'; +import { addHelpMenuToAppChrome, addBadgeToAppChrome } from './utils'; + +export const renderApp = ({ element }: AppMountParameters, services: VisualizeServices) => { + // add help link to visualize docs into app chrome menu + addHelpMenuToAppChrome(services.chrome, services.docLinks); + // add readonly badge if saving restricted + if (!services.visualizeCapabilities.save) { + addBadgeToAppChrome(services.chrome); + } + + const app = ( + + + + + + + + ); + + ReactDOM.render(app, element); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/src/plugins/visualize/public/application/legacy_app.js b/src/plugins/visualize/public/application/legacy_app.js deleted file mode 100644 index 452118f8097da0..00000000000000 --- a/src/plugins/visualize/public/application/legacy_app.js +++ /dev/null @@ -1,261 +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 { find } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { createHashHistory } from 'history'; - -import { createKbnUrlStateStorage, redirectWhenMissing } from '../../../kibana_utils/public'; -import { createSavedSearchesLoader } from '../../../discover/public'; - -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 { - getLandingBreadcrumbs, - getWizardStep1Breadcrumbs, - getCreateBreadcrumbs, - getEditBreadcrumbs, -} from './breadcrumbs'; - -const getResolvedResults = (deps) => { - const { core, data, visualizations, createVisEmbeddableFromObject } = deps; - - const results = {}; - - return (savedVis) => { - results.savedVis = savedVis; - const serializedVis = visualizations.convertToSerializedVis(savedVis); - return visualizations - .createVis(serializedVis.type, serializedVis) - .then((vis) => { - if (vis.type.setup) { - return vis.type.setup(vis).catch(() => vis); - } - return vis; - }) - .then((vis) => { - results.vis = vis; - return createVisEmbeddableFromObject(vis, { - timeRange: data.query.timefilter.timefilter.getTime(), - filters: data.query.filterManager.getFilters(), - }); - }) - .then((embeddableHandler) => { - results.embeddableHandler = embeddableHandler; - - embeddableHandler.getOutput$().subscribe((output) => { - if (output.error) { - core.notifications.toasts.addError(output.error, { - title: i18n.translate('visualize.error.title', { - defaultMessage: 'Visualization error', - }), - }); - } - }); - - if (results.vis.data.savedSearchId) { - return createSavedSearchesLoader({ - savedObjectsClient: core.savedObjects.client, - indexPatterns: data.indexPatterns, - search: data.search, - chrome: core.chrome, - overlays: core.overlays, - }).get(results.vis.data.savedSearchId); - } - }) - .then((savedSearch) => { - if (savedSearch) { - results.savedSearch = savedSearch; - } - return results; - }); - }; -}; - -export function initVisualizeApp(app, deps) { - initVisualizeAppDirective(app, deps); - - app.factory('history', () => createHashHistory()); - app.factory('kbnUrlStateStorage', (history) => - createKbnUrlStateStorage({ - history, - useHash: deps.core.uiSettings.get('state:storeInSessionStorage'), - }) - ); - - app.config(function ($routeProvider) { - const defaults = { - reloadOnSearch: false, - requireUICapability: 'visualize.show', - badge: () => { - if (deps.visualizeCapabilities.save) { - return undefined; - } - - return { - text: i18n.translate('visualize.badge.readOnly.text', { - defaultMessage: 'Read only', - }), - tooltip: i18n.translate('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: (history) => deps.data.indexPatterns.ensureDefaultIndexPattern(history), - }, - }) - .when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, { - ...defaults, - template: visualizeListingTemplate, - k7Breadcrumbs: getWizardStep1Breadcrumbs, - controller: VisualizeListingController, - controllerAs: 'listingController', - resolve: { - createNewVis: () => true, - hasDefaultIndex: (history) => deps.data.indexPatterns.ensureDefaultIndexPattern(history), - }, - }) - .when(VisualizeConstants.CREATE_PATH, { - ...defaults, - template: editorTemplate, - k7Breadcrumbs: getCreateBreadcrumbs, - resolve: { - resolved: function ($route, history) { - const { data, savedVisualizations, visualizations, toastNotifications } = deps; - const visTypes = visualizations.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( - 'visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage', - { - defaultMessage: 'You must provide either an indexPattern or a savedSearchId', - } - ) - ); - } - - // This delay is needed to prevent some navigation issues in Firefox/Safari. - // see https://github.com/elastic/kibana/issues/65161 - const delay = (res) => { - return new Promise((resolve) => { - setTimeout(() => resolve(res), 0); - }); - }; - - return data.indexPatterns - .ensureDefaultIndexPattern(history) - .then(() => savedVisualizations.get($route.current.params)) - .then((savedVis) => { - savedVis.searchSourceFields = { index: $route.current.params.indexPattern }; - return savedVis; - }) - .then(getResolvedResults(deps)) - .then(delay) - .catch( - redirectWhenMissing({ - history, - mapping: VisualizeConstants.LANDING_PAGE_PATH, - toastNotifications, - }) - ); - }, - }, - }) - .when(`${VisualizeConstants.EDIT_PATH}/:id`, { - ...defaults, - template: editorTemplate, - k7Breadcrumbs: getEditBreadcrumbs, - resolve: { - resolved: function ($route, history) { - const { chrome, data, savedVisualizations, toastNotifications } = deps; - - return data.indexPatterns - .ensureDefaultIndexPattern(history) - .then(() => savedVisualizations.get($route.current.params.id)) - .then((savedVis) => { - chrome.recentlyAccessed.add(savedVis.getFullPath(), savedVis.title, savedVis.id); - return savedVis; - }) - .then(getResolvedResults(deps)) - .catch( - redirectWhenMissing({ - history, - navigateToApp: deps.core.application.navigateToApp, - basePath: deps.core.http.basePath, - mapping: { - visualization: VisualizeConstants.LANDING_PAGE_PATH, - search: { - app: 'management', - path: 'kibana/objects/savedVisualizations/' + $route.current.params.id, - }, - 'index-pattern': { - app: 'management', - path: 'kibana/objects/savedVisualizations/' + $route.current.params.id, - }, - 'index-pattern-field': { - app: 'management', - path: 'kibana/objects/savedVisualizations/' + $route.current.params.id, - }, - }, - toastNotifications, - onBeforeRedirect() { - deps.setActiveUrl(VisualizeConstants.LANDING_PAGE_PATH); - }, - }) - ); - }, - }, - }) - .otherwise({ - resolveRedirectTo: function ($rootScope) { - const path = window.location.hash.substr(1); - deps.restorePreviousUrl(); - $rootScope.$applyAsync(() => { - const { navigated } = deps.kibanaLegacy.navigateToLegacyKibanaUrl(path); - if (!navigated) { - deps.kibanaLegacy.navigateToDefaultApp(); - } - }); - // prevent angular from completing the navigation - return new Promise(() => {}); - }, - }); - }); -} diff --git a/src/plugins/visualize/public/application/listing/_index.scss b/src/plugins/visualize/public/application/listing/_index.scss deleted file mode 100644 index 924c164e467d88..00000000000000 --- a/src/plugins/visualize/public/application/listing/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'listing'; diff --git a/src/plugins/visualize/public/application/listing/visualize_listing.html b/src/plugins/visualize/public/application/listing/visualize_listing.html deleted file mode 100644 index 8838348e0b6796..00000000000000 --- a/src/plugins/visualize/public/application/listing/visualize_listing.html +++ /dev/null @@ -1,13 +0,0 @@ -
- -
diff --git a/src/plugins/visualize/public/application/listing/visualize_listing.js b/src/plugins/visualize/public/application/listing/visualize_listing.js deleted file mode 100644 index e8e8d92034113a..00000000000000 --- a/src/plugins/visualize/public/application/listing/visualize_listing.js +++ /dev/null @@ -1,174 +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 { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; -import { withI18nContext } from './visualize_listing_table'; - -import { VisualizeConstants } from '../visualize_constants'; -import { i18n } from '@kbn/i18n'; - -import { getServices } from '../../kibana_services'; -import { syncQueryStateWithUrl } from '../../../../data/public'; -import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../visualizations/public'; - -import { EuiLink } from '@elastic/eui'; -import React from 'react'; - -export function initListingDirective(app, I18nContext) { - app.directive('visualizeListingTable', (reactDirective) => - reactDirective(withI18nContext(I18nContext)) - ); -} - -export function VisualizeListingController($scope, createNewVis, kbnUrlStateStorage, history) { - const { - addBasePath, - chrome, - savedObjectsClient, - savedVisualizations, - data: { query }, - toastNotifications, - visualizations, - core: { docLinks, savedObjects, uiSettings, application }, - savedObjects: savedObjectsPublic, - } = getServices(); - - chrome.docTitle.change( - i18n.translate('visualize.listingPageTitle', { defaultMessage: 'Visualize' }) - ); - - // syncs `_g` portion of url with query services - const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl( - query, - kbnUrlStateStorage - ); - - const { - timefilter: { timefilter }, - } = query; - - timefilter.disableAutoRefreshSelector(); - timefilter.disableTimeRangeSelector(); - - this.addBasePath = addBasePath; - this.uiSettings = uiSettings; - this.savedObjects = savedObjects; - - this.createNewVis = () => { - this.closeNewVisModal = visualizations.showNewVisModal(); - }; - - this.editItem = ({ editUrl, editApp }) => { - if (editApp) { - application.navigateToApp(editApp, { path: editUrl }); - return; - } - // for visualizations the edit and view URLs are the same - window.location.href = addBasePath(editUrl); - }; - - this.getViewElement = (field, record) => { - const dataTestSubj = `visListingTitleLink-${record.title.split(' ').join('-')}`; - if (record.editApp) { - return ( - { - application.navigateToApp(record.editApp, { path: record.editUrl }); - }} - data-test-subj={dataTestSubj} - > - {field} - - ); - } else if (record.editUrl) { - return ( - - {field} - - ); - } else { - return {field}; - } - }; - - if (createNewVis) { - // In case the user navigated to the page via the /visualize/new URL we start the dialog immediately - this.closeNewVisModal = visualizations.showNewVisModal({ - onClose: () => { - // In case the user came via a URL to this page, change the URL to the regular landing page URL after closing the modal - history.push({ - // Should preserve querystring part so the global state is preserved. - ...history.location, - pathname: VisualizeConstants.LANDING_PAGE_PATH, - }); - }, - }); - } - - this.fetchItems = (filter) => { - const isLabsEnabled = uiSettings.get(VISUALIZE_ENABLE_LABS_SETTING); - return savedVisualizations - .findListItems(filter, savedObjectsPublic.settings.getListingLimit()) - .then((result) => { - this.totalItems = result.total; - - return { - total: result.total, - hits: result.hits.filter( - (result) => isLabsEnabled || result.type.stage !== 'experimental' - ), - }; - }); - }; - - this.deleteSelectedItems = function deleteSelectedItems(selectedItems) { - return Promise.all( - selectedItems.map((item) => { - return savedObjectsClient.delete(item.savedObjectType, item.id); - }) - ).catch((error) => { - toastNotifications.addError(error, { - title: i18n.translate('visualize.visualizeListingDeleteErrorTitle', { - defaultMessage: 'Error deleting visualization', - }), - }); - }); - }; - - chrome.setBreadcrumbs([ - { - text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', { - defaultMessage: 'Visualize', - }), - }, - ]); - - this.listingLimit = savedObjectsPublic.settings.getListingLimit(); - this.initialPageSize = savedObjectsPublic.settings.getPerPage(); - - addHelpMenuToAppChrome(chrome, docLinks); - - $scope.$on('$destroy', () => { - if (this.closeNewVisModal) { - this.closeNewVisModal(); - } - - stopSyncingQueryServiceStateWithUrl(); - }); -} diff --git a/src/plugins/visualize/public/application/listing/visualize_listing_table.js b/src/plugins/visualize/public/application/listing/visualize_listing_table.js deleted file mode 100644 index fcd62d7ddee732..00000000000000 --- a/src/plugins/visualize/public/application/listing/visualize_listing_table.js +++ /dev/null @@ -1,233 +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 React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; -import { TableListView } from '../../../../kibana_react/public'; - -import { EuiIcon, EuiBetaBadge, EuiButton, EuiEmptyPrompt } from '@elastic/eui'; - -import { getServices } from '../../kibana_services'; - -class VisualizeListingTable extends Component { - constructor(props) { - super(props); - } - - render() { - const { visualizeCapabilities, core, toastNotifications } = getServices(); - return ( - item.canDelete} - initialFilter={''} - noItemsFragment={this.getNoItemsMessage()} - entityName={i18n.translate('visualize.listing.table.entityName', { - defaultMessage: 'visualization', - })} - entityNamePlural={i18n.translate('visualize.listing.table.entityNamePlural', { - defaultMessage: 'visualizations', - })} - tableListTitle={i18n.translate('visualize.listing.table.listTitle', { - defaultMessage: 'Visualizations', - })} - toastNotifications={toastNotifications} - uiSettings={core.uiSettings} - /> - ); - } - - getTableColumns() { - const tableColumns = [ - { - field: 'title', - name: i18n.translate('visualize.listing.table.titleColumnName', { - defaultMessage: 'Title', - }), - sortable: true, - render: (field, record) => this.props.getViewElement(field, record), - }, - { - field: 'typeTitle', - name: i18n.translate('visualize.listing.table.typeColumnName', { - defaultMessage: 'Type', - }), - sortable: true, - render: (field, record) => ( - - {this.renderItemTypeIcon(record)} - {record.typeTitle} - {this.getBadge(record)} - - ), - }, - { - field: 'description', - name: i18n.translate('visualize.listing.table.descriptionColumnName', { - defaultMessage: 'Description', - }), - sortable: true, - render: (field, record) => {record.description}, - }, - ]; - - return tableColumns; - } - - getNoItemsMessage() { - if (this.props.hideWriteControls) { - return ( -
- - - - } - /> -
- ); - } - - return ( -
- - - - } - body={ - -

- -

-
- } - actions={ - - - - } - /> -
- ); - } - - renderItemTypeIcon(item) { - let icon; - if (item.image) { - icon = ( - - ); - } else { - icon = ( -