diff --git a/docs/development/core/public/kibana-plugin-public.ianonymouspaths.isanonymous.md b/docs/development/core/public/kibana-plugin-public.ianonymouspaths.isanonymous.md
index 92a87668b6ef0..d6be78e1e725b 100644
--- a/docs/development/core/public/kibana-plugin-public.ianonymouspaths.isanonymous.md
+++ b/docs/development/core/public/kibana-plugin-public.ianonymouspaths.isanonymous.md
@@ -4,7 +4,7 @@
## IAnonymousPaths.isAnonymous() method
-Determines whether the provided path doesn't require authentication
+Determines whether the provided path doesn't require authentication. `path` should include the current basePath.
Signature:
diff --git a/docs/development/core/public/kibana-plugin-public.ianonymouspaths.md b/docs/development/core/public/kibana-plugin-public.ianonymouspaths.md
index 3e5caf49695c2..1290df28780cf 100644
--- a/docs/development/core/public/kibana-plugin-public.ianonymouspaths.md
+++ b/docs/development/core/public/kibana-plugin-public.ianonymouspaths.md
@@ -16,6 +16,6 @@ export interface IAnonymousPaths
| Method | Description |
| --- | --- |
-| [isAnonymous(path)](./kibana-plugin-public.ianonymouspaths.isanonymous.md) | Determines whether the provided path doesn't require authentication |
-| [register(path)](./kibana-plugin-public.ianonymouspaths.register.md) | Register path
as not requiring authentication |
+| [isAnonymous(path)](./kibana-plugin-public.ianonymouspaths.isanonymous.md) | Determines whether the provided path doesn't require authentication. path
should include the current basePath. |
+| [register(path)](./kibana-plugin-public.ianonymouspaths.register.md) | Register path
as not requiring authentication. path
should not include the current basePath. |
diff --git a/docs/development/core/public/kibana-plugin-public.ianonymouspaths.register.md b/docs/development/core/public/kibana-plugin-public.ianonymouspaths.register.md
index 88c615da05155..3ab9bf438aa16 100644
--- a/docs/development/core/public/kibana-plugin-public.ianonymouspaths.register.md
+++ b/docs/development/core/public/kibana-plugin-public.ianonymouspaths.register.md
@@ -4,7 +4,7 @@
## IAnonymousPaths.register() method
-Register `path` as not requiring authentication
+Register `path` as not requiring authentication. `path` should not include the current basePath.
Signature:
diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md
index 253e50f0f2c2e..df0b963e2b627 100644
--- a/docs/development/core/public/kibana-plugin-public.md
+++ b/docs/development/core/public/kibana-plugin-public.md
@@ -121,5 +121,5 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [ToastInputFields](./kibana-plugin-public.toastinputfields.md) | Allowed fields for [ToastInput](./kibana-plugin-public.toastinput.md). |
| [ToastsSetup](./kibana-plugin-public.toastssetup.md) | [IToasts](./kibana-plugin-public.itoasts.md) |
| [ToastsStart](./kibana-plugin-public.toastsstart.md) | [IToasts](./kibana-plugin-public.itoasts.md) |
-| [UiSettingsClientContract](./kibana-plugin-public.uisettingsclientcontract.md) | [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md) |
+| [UiSettingsClientContract](./kibana-plugin-public.uisettingsclientcontract.md) | Client-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. [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md) |
diff --git a/docs/development/core/public/kibana-plugin-public.uisettingsclient.getall.md b/docs/development/core/public/kibana-plugin-public.uisettingsclient.getall.md
index 5eaf06e7dd682..06daf8e8151cd 100644
--- a/docs/development/core/public/kibana-plugin-public.uisettingsclient.getall.md
+++ b/docs/development/core/public/kibana-plugin-public.uisettingsclient.getall.md
@@ -9,9 +9,9 @@ Gets the metadata about all uiSettings, including the type, default value, and u
Signature:
```typescript
-getAll(): UiSettingsState;
+getAll(): Record>;
```
Returns:
-`UiSettingsState`
+`Record>`
diff --git a/docs/development/core/public/kibana-plugin-public.uisettingsclientcontract.md b/docs/development/core/public/kibana-plugin-public.uisettingsclientcontract.md
index 6eda1fd3274c6..7173386d88265 100644
--- a/docs/development/core/public/kibana-plugin-public.uisettingsclientcontract.md
+++ b/docs/development/core/public/kibana-plugin-public.uisettingsclientcontract.md
@@ -4,7 +4,7 @@
## UiSettingsClientContract type
-[UiSettingsClient](./kibana-plugin-public.uisettingsclient.md)
+Client-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. [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md)
Signature:
diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.md b/docs/development/core/server/kibana-plugin-server.coresetup.md
index a6dda69fd154e..c51459bc41a43 100644
--- a/docs/development/core/server/kibana-plugin-server.coresetup.md
+++ b/docs/development/core/server/kibana-plugin-server.coresetup.md
@@ -19,4 +19,5 @@ export interface CoreSetup
| [context](./kibana-plugin-server.coresetup.context.md) | ContextSetup
| [ContextSetup](./kibana-plugin-server.contextsetup.md) |
| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | ElasticsearchServiceSetup
| [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) |
| [http](./kibana-plugin-server.coresetup.http.md) | HttpServiceSetup
| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) |
+| [uiSettings](./kibana-plugin-server.coresetup.uisettings.md) | UiSettingsServiceSetup
| [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) |
diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.uisettings.md b/docs/development/core/server/kibana-plugin-server.coresetup.uisettings.md
new file mode 100644
index 0000000000000..54120d7c3fa8d
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.coresetup.uisettings.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [CoreSetup](./kibana-plugin-server.coresetup.md) > [uiSettings](./kibana-plugin-server.coresetup.uisettings.md)
+
+## CoreSetup.uiSettings property
+
+[UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md)
+
+Signature:
+
+```typescript
+uiSettings: UiSettingsServiceSetup;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getdefaults.md b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getdefaults.md
deleted file mode 100644
index 29faa6d945b43..0000000000000
--- a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getdefaults.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IUiSettingsClient](./kibana-plugin-server.iuisettingsclient.md) > [getDefaults](./kibana-plugin-server.iuisettingsclient.getdefaults.md)
-
-## IUiSettingsClient.getDefaults property
-
-Returns uiSettings default values [UiSettingsParams](./kibana-plugin-server.uisettingsparams.md)
-
-Signature:
-
-```typescript
-getDefaults: () => Record;
-```
diff --git a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getregistered.md b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getregistered.md
new file mode 100644
index 0000000000000..16ae4c3dd8b36
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getregistered.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IUiSettingsClient](./kibana-plugin-server.iuisettingsclient.md) > [getRegistered](./kibana-plugin-server.iuisettingsclient.getregistered.md)
+
+## IUiSettingsClient.getRegistered property
+
+Returns registered uiSettings values [UiSettingsParams](./kibana-plugin-server.uisettingsparams.md)
+
+Signature:
+
+```typescript
+getRegistered: () => Readonly>;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getuserprovided.md b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getuserprovided.md
index 9a449b64ed5d0..134039cfa91f3 100644
--- a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getuserprovided.md
+++ b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.getuserprovided.md
@@ -9,8 +9,5 @@ Retrieves a set of all uiSettings values set by the user.
Signature:
```typescript
-getUserProvided: () => Promise>;
+getUserProvided: () => Promise>>;
```
diff --git a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md
index 142f33d27c385..a4697ddbbb85e 100644
--- a/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md
+++ b/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md
@@ -4,7 +4,7 @@
## IUiSettingsClient interface
-Service that provides access to the UiSettings stored in elasticsearch.
+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.
Signature:
@@ -18,8 +18,8 @@ export interface IUiSettingsClient
| --- | --- | --- |
| [get](./kibana-plugin-server.iuisettingsclient.get.md) | <T extends SavedObjectAttribute = any>(key: string) => Promise<T>
| Retrieves uiSettings values set by the user with fallbacks to default values if not specified. |
| [getAll](./kibana-plugin-server.iuisettingsclient.getall.md) | <T extends SavedObjectAttribute = any>() => Promise<Record<string, T>>
| Retrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified. |
-| [getDefaults](./kibana-plugin-server.iuisettingsclient.getdefaults.md) | () => Record<string, UiSettingsParams>
| Returns uiSettings default values [UiSettingsParams](./kibana-plugin-server.uisettingsparams.md) |
-| [getUserProvided](./kibana-plugin-server.iuisettingsclient.getuserprovided.md) | <T extends SavedObjectAttribute = any>() => Promise<Record<string, {
userValue?: T;
isOverridden?: boolean;
}>>
| Retrieves a set of all uiSettings values set by the user. |
+| [getRegistered](./kibana-plugin-server.iuisettingsclient.getregistered.md) | () => Readonly<Record<string, UiSettingsParams>>
| Returns registered uiSettings values [UiSettingsParams](./kibana-plugin-server.uisettingsparams.md) |
+| [getUserProvided](./kibana-plugin-server.iuisettingsclient.getuserprovided.md) | <T extends SavedObjectAttribute = any>() => Promise<Record<string, UserProvidedValues<T>>>
| Retrieves a set of all uiSettings values set by the user. |
| [isOverridden](./kibana-plugin-server.iuisettingsclient.isoverridden.md) | (key: string) => boolean
| Shows whether the uiSettings value set by the user. |
| [remove](./kibana-plugin-server.iuisettingsclient.remove.md) | (key: string) => Promise<void>
| Removes uiSettings value by key. |
| [removeMany](./kibana-plugin-server.iuisettingsclient.removemany.md) | (keys: string[]) => Promise<void>
| Removes multiple uiSettings values by keys. |
diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md
index 5a8b702e0ec99..9907750b8742f 100644
--- a/docs/development/core/server/kibana-plugin-server.md
+++ b/docs/development/core/server/kibana-plugin-server.md
@@ -63,7 +63,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [IKibanaSocket](./kibana-plugin-server.ikibanasocket.md) | A tiny abstraction for TCP socket. |
| [IndexSettingsDeprecationInfo](./kibana-plugin-server.indexsettingsdeprecationinfo.md) | |
| [IRouter](./kibana-plugin-server.irouter.md) | Registers route handlers for specified resource path and method. See [RouteConfig](./kibana-plugin-server.routeconfig.md) and [RequestHandler](./kibana-plugin-server.requesthandler.md) for more information about arguments to route registrations. |
-| [IUiSettingsClient](./kibana-plugin-server.iuisettingsclient.md) | Service that provides access to the UiSettings stored in elasticsearch. |
+| [IUiSettingsClient](./kibana-plugin-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. |
| [KibanaRequestRoute](./kibana-plugin-server.kibanarequestroute.md) | Request specific route information exposed to a handler. |
| [LegacyRequest](./kibana-plugin-server.legacyrequest.md) | |
| [LegacyServiceSetupDeps](./kibana-plugin-server.legacyservicesetupdeps.md) | |
@@ -118,6 +118,8 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [SessionStorageCookieOptions](./kibana-plugin-server.sessionstoragecookieoptions.md) | Configuration used to create HTTP session storage based on top of cookie mechanism. |
| [SessionStorageFactory](./kibana-plugin-server.sessionstoragefactory.md) | SessionStorage factory to bind one to an incoming request |
| [UiSettingsParams](./kibana-plugin-server.uisettingsparams.md) | UiSettings parameters defined by the plugins. |
+| [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) | |
+| [UserProvidedValues](./kibana-plugin-server.userprovidedvalues.md) | Describes the values explicitly set by user. |
## Variables
diff --git a/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md b/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md
index e1ea358320b9a..2d8b27ecb6c67 100644
--- a/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md
+++ b/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md
@@ -15,5 +15,8 @@ core: {
dataClient: IScopedClusterClient;
adminClient: IScopedClusterClient;
};
+ uiSettings: {
+ client: IUiSettingsClient;
+ };
};
```
diff --git a/docs/development/core/server/kibana-plugin-server.requesthandlercontext.md b/docs/development/core/server/kibana-plugin-server.requesthandlercontext.md
index 37a40f98adef3..c9fc80596efa9 100644
--- a/docs/development/core/server/kibana-plugin-server.requesthandlercontext.md
+++ b/docs/development/core/server/kibana-plugin-server.requesthandlercontext.md
@@ -18,5 +18,5 @@ export interface RequestHandlerContext
| Property | Type | Description |
| --- | --- | --- |
-| [core](./kibana-plugin-server.requesthandlercontext.core.md) | {
savedObjects: {
client: SavedObjectsClientContract;
};
elasticsearch: {
dataClient: IScopedClusterClient;
adminClient: IScopedClusterClient;
};
}
| |
+| [core](./kibana-plugin-server.requesthandlercontext.core.md) | {
savedObjects: {
client: SavedObjectsClientContract;
};
elasticsearch: {
dataClient: IScopedClusterClient;
adminClient: IScopedClusterClient;
};
uiSettings: {
client: IUiSettingsClient;
};
}
| |
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsparams.category.md b/docs/development/core/server/kibana-plugin-server.uisettingsparams.category.md
index 47aedbfbf2810..6bf1b17dc947a 100644
--- a/docs/development/core/server/kibana-plugin-server.uisettingsparams.category.md
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsparams.category.md
@@ -9,5 +9,5 @@ used to group the configured setting in the UI
Signature:
```typescript
-category: string[];
+category?: string[];
```
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsparams.description.md b/docs/development/core/server/kibana-plugin-server.uisettingsparams.description.md
index 8d8887285ae2e..6a203629f5425 100644
--- a/docs/development/core/server/kibana-plugin-server.uisettingsparams.description.md
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsparams.description.md
@@ -9,5 +9,5 @@ description provided to a user in UI
Signature:
```typescript
-description: string;
+description?: string;
```
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsparams.md b/docs/development/core/server/kibana-plugin-server.uisettingsparams.md
index 275111c05eff9..a38499e8f37dd 100644
--- a/docs/development/core/server/kibana-plugin-server.uisettingsparams.md
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsparams.md
@@ -20,7 +20,7 @@ export interface UiSettingsParams
| [description](./kibana-plugin-server.uisettingsparams.description.md) | string
| description provided to a user in UI |
| [name](./kibana-plugin-server.uisettingsparams.name.md) | string
| title in the UI |
| [optionLabels](./kibana-plugin-server.uisettingsparams.optionlabels.md) | Record<string, string>
| text labels for 'select' type UI element |
-| [options](./kibana-plugin-server.uisettingsparams.options.md) | string[]
| a range of valid values |
+| [options](./kibana-plugin-server.uisettingsparams.options.md) | string[]
| array of permitted values for this setting |
| [readonly](./kibana-plugin-server.uisettingsparams.readonly.md) | boolean
| a flag indicating that value cannot be changed |
| [requiresPageReload](./kibana-plugin-server.uisettingsparams.requirespagereload.md) | boolean
| a flag indicating whether new value applying requires page reloading |
| [type](./kibana-plugin-server.uisettingsparams.type.md) | UiSettingsType
| defines a type of UI element [UiSettingsType](./kibana-plugin-server.uisettingstype.md) |
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsparams.name.md b/docs/development/core/server/kibana-plugin-server.uisettingsparams.name.md
index 2b414eefffed2..07905ca7de20a 100644
--- a/docs/development/core/server/kibana-plugin-server.uisettingsparams.name.md
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsparams.name.md
@@ -9,5 +9,5 @@ title in the UI
Signature:
```typescript
-name: string;
+name?: string;
```
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsparams.options.md b/docs/development/core/server/kibana-plugin-server.uisettingsparams.options.md
index 71eecdfabc4a0..2220feab74ffd 100644
--- a/docs/development/core/server/kibana-plugin-server.uisettingsparams.options.md
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsparams.options.md
@@ -4,7 +4,7 @@
## UiSettingsParams.options property
-a range of valid values
+array of permitted values for this setting
Signature:
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsparams.value.md b/docs/development/core/server/kibana-plugin-server.uisettingsparams.value.md
index 455756899ecfc..397498ccf5c11 100644
--- a/docs/development/core/server/kibana-plugin-server.uisettingsparams.value.md
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsparams.value.md
@@ -9,5 +9,5 @@ default value to fall back to if a user doesn't provide any
Signature:
```typescript
-value: SavedObjectAttribute;
+value?: SavedObjectAttribute;
```
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.md b/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.md
new file mode 100644
index 0000000000000..8dde78f633d88
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.md
@@ -0,0 +1,19 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md)
+
+## UiSettingsServiceSetup interface
+
+
+Signature:
+
+```typescript
+export interface UiSettingsServiceSetup
+```
+
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [register(settings)](./kibana-plugin-server.uisettingsservicesetup.register.md) | Sets settings with default values for the uiSettings. |
+
diff --git a/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.register.md b/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.register.md
new file mode 100644
index 0000000000000..8091a7cec44aa
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.register.md
@@ -0,0 +1,28 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) > [register](./kibana-plugin-server.uisettingsservicesetup.register.md)
+
+## UiSettingsServiceSetup.register() method
+
+Sets settings with default values for the uiSettings.
+
+Signature:
+
+```typescript
+register(settings: Record): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| settings | Record<string, UiSettingsParams>
| |
+
+Returns:
+
+`void`
+
+## Example
+
+setup(core: CoreSetup){ core.uiSettings.register(\[{ foo: { name: i18n.translate('my foo settings'), value: true, description: 'add some awesomeness', }, }\]); }
+
diff --git a/docs/development/core/server/kibana-plugin-server.userprovidedvalues.isoverridden.md b/docs/development/core/server/kibana-plugin-server.userprovidedvalues.isoverridden.md
new file mode 100644
index 0000000000000..01e04b490595d
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.userprovidedvalues.isoverridden.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [UserProvidedValues](./kibana-plugin-server.userprovidedvalues.md) > [isOverridden](./kibana-plugin-server.userprovidedvalues.isoverridden.md)
+
+## UserProvidedValues.isOverridden property
+
+Signature:
+
+```typescript
+isOverridden?: boolean;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.userprovidedvalues.md b/docs/development/core/server/kibana-plugin-server.userprovidedvalues.md
new file mode 100644
index 0000000000000..7b2114404d7f2
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.userprovidedvalues.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [UserProvidedValues](./kibana-plugin-server.userprovidedvalues.md)
+
+## UserProvidedValues interface
+
+Describes the values explicitly set by user.
+
+Signature:
+
+```typescript
+export interface UserProvidedValues
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [isOverridden](./kibana-plugin-server.userprovidedvalues.isoverridden.md) | boolean
| |
+| [userValue](./kibana-plugin-server.userprovidedvalues.uservalue.md) | T
| |
+
diff --git a/docs/development/core/server/kibana-plugin-server.userprovidedvalues.uservalue.md b/docs/development/core/server/kibana-plugin-server.userprovidedvalues.uservalue.md
new file mode 100644
index 0000000000000..59d25651b7697
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.userprovidedvalues.uservalue.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [UserProvidedValues](./kibana-plugin-server.userprovidedvalues.md) > [userValue](./kibana-plugin-server.userprovidedvalues.uservalue.md)
+
+## UserProvidedValues.userValue property
+
+Signature:
+
+```typescript
+userValue?: T;
+```
diff --git a/package.json b/package.json
index 289c2e8b0a8d0..604c3277415dd 100644
--- a/package.json
+++ b/package.json
@@ -341,6 +341,7 @@
"@types/strip-ansi": "^3.0.0",
"@types/styled-components": "^3.0.2",
"@types/supertest": "^2.0.5",
+ "@types/supertest-as-promised": "^2.0.38",
"@types/type-detect": "^4.0.1",
"@types/uuid": "^3.4.4",
"@types/vinyl-fs": "^2.4.11",
diff --git a/renovate.json5 b/renovate.json5
index 2d068f55bc61a..0c288bb85c72c 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -569,6 +569,14 @@
'@types/supertest',
],
},
+ {
+ groupSlug: 'supertest-as-promised',
+ groupName: 'supertest-as-promised related packages',
+ packageNames: [
+ 'supertest-as-promised',
+ '@types/supertest-as-promised',
+ ],
+ },
{
groupSlug: 'type-detect',
groupName: 'type-detect related packages',
diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md
index 018a91be4c3d1..43dc77252d6bb 100644
--- a/src/core/MIGRATION.md
+++ b/src/core/MIGRATION.md
@@ -1198,7 +1198,7 @@ This table shows where these uiExports have moved to in the New Platform. In mos
| `styleSheetPaths` | | |
| `taskDefinitions` | | Should be an API on the taskManager plugin. |
| `uiCapabilities` | [`core.application.register`](/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md) | |
-| `uiSettingDefaults` | | Most likely part of server-side UiSettingsService. |
+| `uiSettingDefaults` | [`core.uiSettings.register`](/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.md) | |
| `validations` | | Part of SavedObjects, see [#33587](https://github.com/elastic/kibana/issues/33587) |
| `visEditorTypes` | | |
| `visTypeEnhancers` | | |
diff --git a/src/core/public/injected_metadata/injected_metadata_service.ts b/src/core/public/injected_metadata/injected_metadata_service.ts
index 478285a70771e..a5342aaa48b72 100644
--- a/src/core/public/injected_metadata/injected_metadata_service.ts
+++ b/src/core/public/injected_metadata/injected_metadata_service.ts
@@ -19,8 +19,12 @@
import { get } from 'lodash';
import { DiscoveredPlugin, PluginName } from '../../server';
-import { EnvironmentMode, PackageInfo } from '../../server/types';
-import { UiSettingsState } from '../ui_settings';
+import {
+ EnvironmentMode,
+ PackageInfo,
+ UiSettingsParams,
+ UserProvidedValues,
+} from '../../server/types';
import { deepFreeze } from '../../utils/';
import { Capabilities } from '..';
@@ -69,8 +73,8 @@ export interface InjectedMetadataParams {
serverName: string;
devMode: boolean;
uiSettings: {
- defaults: UiSettingsState;
- user?: UiSettingsState;
+ defaults: Record;
+ user?: Record;
};
};
};
@@ -179,8 +183,8 @@ export interface InjectedMetadataSetup {
serverName: string;
devMode: boolean;
uiSettings: {
- defaults: UiSettingsState;
- user?: UiSettingsState | undefined;
+ defaults: Record;
+ user?: Record | undefined;
};
};
getInjectedVar: (name: string, defaultValue?: any) => unknown;
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index 416fb13cbb73e..a596ea394abda 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -11,6 +11,8 @@ import React from 'react';
import * as Rx from 'rxjs';
import { ShallowPromise } from '@kbn/utility-types';
import { EuiGlobalToastListToast as Toast } from '@elastic/eui';
+import { UiSettingsParams as UiSettingsParams_2 } from 'src/core/server/types';
+import { UserProvidedValues as UserProvidedValues_2 } from 'src/core/server/types';
// @public
export interface App extends AppBase {
@@ -957,7 +959,7 @@ export class UiSettingsClient {
constructor(params: UiSettingsClientParams);
get$(key: string, defaultOverride?: any): Rx.Observable;
get(key: string, defaultOverride?: any): any;
- getAll(): UiSettingsState;
+ getAll(): Record>;
getSaved$(): Rx.Observable<{
key: string;
newValue: any;
@@ -979,16 +981,13 @@ export class UiSettingsClient {
stop(): void;
}
-// @public (undocumented)
+// @public
export type UiSettingsClientContract = PublicMethodsOf;
// @public (undocumented)
export interface UiSettingsState {
- // Warning: (ae-forgotten-export) The symbol "InjectedUiSettingsDefault" needs to be exported by the entry point index.d.ts
- // Warning: (ae-forgotten-export) The symbol "InjectedUiSettingsUser" needs to be exported by the entry point index.d.ts
- //
// (undocumented)
- [key: string]: InjectedUiSettingsDefault & InjectedUiSettingsUser;
+ [key: string]: UiSettingsParams_2 & UserProvidedValues_2;
}
diff --git a/src/core/public/ui_settings/types.ts b/src/core/public/ui_settings/types.ts
index d1cf25c3e9e6f..24e87eb04f026 100644
--- a/src/core/public/ui_settings/types.ts
+++ b/src/core/public/ui_settings/types.ts
@@ -17,28 +17,9 @@
* under the License.
*/
-// properties that come from legacyInjectedMetadata.uiSettings.defaults
-interface InjectedUiSettingsDefault {
- name?: string;
- value?: any;
- description?: string;
- category?: string[];
- type?: string;
- readOnly?: boolean;
- options?: string[] | { [key: string]: any };
- /**
- * Whether a change in that setting will only take affect after a page reload.
- */
- requiresPageReload?: boolean;
-}
-
-// properties that come from legacyInjectedMetadata.uiSettings.user
-interface InjectedUiSettingsUser {
- userValue?: any;
- isOverridden?: boolean;
-}
+import { UiSettingsParams, UserProvidedValues } from 'src/core/server/types';
/** @public */
export interface UiSettingsState {
- [key: string]: InjectedUiSettingsDefault & InjectedUiSettingsUser;
+ [key: string]: UiSettingsParams & UserProvidedValues;
}
diff --git a/src/core/public/ui_settings/ui_settings_client.ts b/src/core/public/ui_settings/ui_settings_client.ts
index 3083851dd453d..c3190847130d5 100644
--- a/src/core/public/ui_settings/ui_settings_client.ts
+++ b/src/core/public/ui_settings/ui_settings_client.ts
@@ -21,18 +21,25 @@ import { cloneDeep, defaultsDeep } from 'lodash';
import * as Rx from 'rxjs';
import { filter, map } from 'rxjs/operators';
+import { UiSettingsParams, UserProvidedValues } from 'src/core/server/types';
import { UiSettingsState } from './types';
+
import { UiSettingsApi } from './ui_settings_api';
/** @public */
interface UiSettingsClientParams {
api: UiSettingsApi;
- defaults: UiSettingsState;
+ defaults: Record;
initialSettings?: UiSettingsState;
}
/**
+ * Client-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.
* {@link UiSettingsClient}
+ *
* @public
*/
export type UiSettingsClientContract = PublicMethodsOf;
@@ -44,8 +51,8 @@ export class UiSettingsClient {
private readonly updateErrors$ = new Rx.Subject();
private readonly api: UiSettingsApi;
- private readonly defaults: UiSettingsState;
- private cache: UiSettingsState;
+ private readonly defaults: Record;
+ private cache: Record;
constructor(params: UiSettingsClientParams) {
this.api = params.api;
diff --git a/src/core/server/http/router/response_adapter.ts b/src/core/server/http/router/response_adapter.ts
index fe6cb32d21776..e5dabc99f4442 100644
--- a/src/core/server/http/router/response_adapter.ts
+++ b/src/core/server/http/router/response_adapter.ts
@@ -120,7 +120,11 @@ export class HapiResponseAdapter {
});
error.output.payload.message = getErrorMessage(payload);
- error.output.payload.attributes = getErrorAttributes(payload);
+
+ const attributes = getErrorAttributes(payload);
+ if (attributes) {
+ error.output.payload.attributes = attributes;
+ }
const headers = kibanaResponse.options.headers;
if (headers) {
diff --git a/src/core/server/index.ts b/src/core/server/index.ts
index c3f63c7c26e97..35e83da4ef30c 100644
--- a/src/core/server/index.ts
+++ b/src/core/server/index.ts
@@ -49,7 +49,11 @@ import { PluginsServiceSetup, PluginsServiceStart, PluginOpaqueId } from './plug
import { ContextSetup } from './context';
import { SavedObjectsServiceStart } from './saved_objects';
-import { InternalUiSettingsServiceSetup } from './ui_settings';
+import {
+ InternalUiSettingsServiceSetup,
+ IUiSettingsClient,
+ UiSettingsServiceSetup,
+} from './ui_settings';
import { SavedObjectsClientContract } from './saved_objects/types';
export { bootstrap } from './bootstrap';
@@ -175,6 +179,8 @@ export {
UiSettingsParams,
InternalUiSettingsServiceSetup,
UiSettingsType,
+ UiSettingsServiceSetup,
+ UserProvidedValues,
} from './ui_settings';
export { RecursiveReadonly } from '../utils';
@@ -216,6 +222,9 @@ export interface RequestHandlerContext {
dataClient: IScopedClusterClient;
adminClient: IScopedClusterClient;
};
+ uiSettings: {
+ client: IUiSettingsClient;
+ };
};
}
@@ -231,6 +240,8 @@ export interface CoreSetup {
elasticsearch: ElasticsearchServiceSetup;
/** {@link HttpServiceSetup} */
http: HttpServiceSetup;
+ /** {@link UiSettingsServiceSetup} */
+ uiSettings: UiSettingsServiceSetup;
}
/**
diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts
index 590bd192e3ded..e2aefd846d978 100644
--- a/src/core/server/legacy/legacy_service.test.ts
+++ b/src/core/server/legacy/legacy_service.test.ts
@@ -72,7 +72,7 @@ beforeEach(() => {
core: {
context: contextServiceMock.createSetupContract(),
elasticsearch: { legacy: {} } as any,
- uiSettings: uiSettingsServiceMock.createSetup(),
+ uiSettings: uiSettingsServiceMock.createSetupContract(),
http: {
...httpServiceMock.createSetupContract(),
auth: {
diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts
index dd3ee3db89153..b7c55a8af7c18 100644
--- a/src/core/server/legacy/legacy_service.ts
+++ b/src/core/server/legacy/legacy_service.ts
@@ -248,6 +248,9 @@ export class LegacyService implements CoreService {
basePath: setupDeps.core.http.basePath,
isTlsEnabled: setupDeps.core.http.isTlsEnabled,
},
+ uiSettings: {
+ register: setupDeps.core.uiSettings.register,
+ },
};
const coreStart: CoreStart = {};
diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts
index deb5984564db1..b51d5302e3274 100644
--- a/src/core/server/mocks.ts
+++ b/src/core/server/mocks.ts
@@ -22,6 +22,7 @@ import { loggingServiceMock } from './logging/logging_service.mock';
import { elasticsearchServiceMock } from './elasticsearch/elasticsearch_service.mock';
import { httpServiceMock } from './http/http_service.mock';
import { contextServiceMock } from './context/context_service.mock';
+import { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock';
export { httpServerMock } from './http/http_server.mocks';
export { sessionStorageMock } from './http/cookie_session_storage.mocks';
@@ -79,10 +80,14 @@ function createCoreSetupMock() {
};
httpMock.createRouter.mockImplementation(() => httpService.createRouter(''));
+ const uiSettingsMock = {
+ register: uiSettingsServiceMock.createSetupContract().register,
+ };
const mock: MockedKeys = {
context: contextServiceMock.createSetupContract(),
elasticsearch: elasticsearchServiceMock.createSetupContract(),
http: httpMock,
+ uiSettings: uiSettingsMock,
};
return mock;
@@ -94,8 +99,19 @@ function createCoreStartMock() {
return mock;
}
+function createInternalCoreSetupMock() {
+ const setupDeps = {
+ context: contextServiceMock.createSetupContract(),
+ elasticsearch: elasticsearchServiceMock.createSetupContract(),
+ http: httpServiceMock.createSetupContract(),
+ uiSettings: uiSettingsServiceMock.createSetupContract(),
+ };
+ return setupDeps;
+}
+
export const coreMock = {
createSetup: createCoreSetupMock,
createStart: createCoreStartMock,
+ createInternalSetup: createInternalCoreSetupMock,
createPluginInitializerContext: pluginInitializerContextMock,
};
diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts
index 5c57a5fa2c8d1..e457f01a1941c 100644
--- a/src/core/server/plugins/plugin.test.ts
+++ b/src/core/server/plugins/plugin.test.ts
@@ -24,15 +24,13 @@ import { schema } from '@kbn/config-schema';
import { Env } from '../config';
import { getEnvOptions } from '../config/__mocks__/env';
import { CoreContext } from '../core_context';
+import { coreMock } from '../mocks';
import { configServiceMock } from '../config/config_service.mock';
-import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
-import { httpServiceMock } from '../http/http_service.mock';
import { loggingServiceMock } from '../logging/logging_service.mock';
import { PluginWrapper } from './plugin';
import { PluginManifest } from './types';
import { createPluginInitializerContext, createPluginSetupContext } from './plugin_context';
-import { contextServiceMock } from '../context/context_service.mock';
const mockPluginInitializer = jest.fn();
const logger = loggingServiceMock.create();
@@ -68,11 +66,7 @@ configService.atPath.mockReturnValue(new BehaviorSubject({ initialize: true }));
let coreId: symbol;
let env: Env;
let coreContext: CoreContext;
-const setupDeps = {
- context: contextServiceMock.createSetupContract(),
- elasticsearch: elasticsearchServiceMock.createSetupContract(),
- http: httpServiceMock.createSetupContract(),
-};
+const setupDeps = coreMock.createInternalSetup();
beforeEach(() => {
coreId = Symbol('core');
env = Env.createDefault(getEnvOptions());
diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts
index edcafbb9a3dc3..9885a572ad8c0 100644
--- a/src/core/server/plugins/plugin_context.ts
+++ b/src/core/server/plugins/plugin_context.ts
@@ -123,6 +123,9 @@ export function createPluginSetupContext(
basePath: deps.http.basePath,
isTlsEnabled: deps.http.isTlsEnabled,
},
+ uiSettings: {
+ register: deps.uiSettings.register,
+ },
};
}
diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts
index d25f9087432bd..0b3bc0759463c 100644
--- a/src/core/server/plugins/plugins_service.test.ts
+++ b/src/core/server/plugins/plugins_service.test.ts
@@ -25,15 +25,13 @@ import { schema } from '@kbn/config-schema';
import { Config, ConfigPath, ConfigService, Env, ObjectToConfigAdapter } from '../config';
import { getEnvOptions } from '../config/__mocks__/env';
-import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
-import { httpServiceMock } from '../http/http_service.mock';
+import { coreMock } from '../mocks';
import { loggingServiceMock } from '../logging/logging_service.mock';
import { PluginDiscoveryError } from './discovery';
import { PluginWrapper } from './plugin';
import { PluginsService } from './plugins_service';
import { PluginsSystem } from './plugins_system';
import { config } from './plugins_config';
-import { contextServiceMock } from '../context/context_service.mock';
const MockPluginsSystem: jest.Mock = PluginsSystem as any;
@@ -42,11 +40,7 @@ let configService: ConfigService;
let coreId: symbol;
let env: Env;
let mockPluginSystem: jest.Mocked;
-const setupDeps = {
- context: contextServiceMock.createSetupContract(),
- elasticsearch: elasticsearchServiceMock.createSetupContract(),
- http: httpServiceMock.createSetupContract(),
-};
+const setupDeps = coreMock.createInternalSetup();
const logger = loggingServiceMock.create();
['path-1', 'path-2', 'path-3', 'path-4', 'path-5'].forEach(path => {
diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts
index 92b537deae337..2964e34c370b1 100644
--- a/src/core/server/plugins/plugins_service.ts
+++ b/src/core/server/plugins/plugins_service.ts
@@ -21,15 +21,14 @@ import { Observable } from 'rxjs';
import { filter, first, map, mergeMap, tap, toArray } from 'rxjs/operators';
import { CoreService } from '../../types';
import { CoreContext } from '../core_context';
-import { InternalElasticsearchServiceSetup } from '../elasticsearch';
-import { InternalHttpServiceSetup } from '../http';
+
import { Logger } from '../logging';
import { discover, PluginDiscoveryError, PluginDiscoveryErrorType } from './discovery';
import { PluginWrapper } from './plugin';
import { DiscoveredPlugin, DiscoveredPluginInternal, PluginName } from './types';
import { PluginsConfig, PluginsConfigType } from './plugins_config';
import { PluginsSystem } from './plugins_system';
-import { ContextSetup } from '../context';
+import { InternalCoreSetup } from '..';
/** @public */
export interface PluginsServiceSetup {
@@ -46,11 +45,7 @@ export interface PluginsServiceStart {
}
/** @internal */
-export interface PluginsServiceSetupDeps {
- context: ContextSetup;
- elasticsearch: InternalElasticsearchServiceSetup;
- http: InternalHttpServiceSetup;
-}
+export type PluginsServiceSetupDeps = InternalCoreSetup;
/** @internal */
export interface PluginsServiceStartDeps {} // eslint-disable-line @typescript-eslint/no-empty-interface
diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts
index f67bd371ff565..efd53681d6cd0 100644
--- a/src/core/server/plugins/plugins_system.test.ts
+++ b/src/core/server/plugins/plugins_system.test.ts
@@ -28,13 +28,13 @@ import { Env } from '../config';
import { getEnvOptions } from '../config/__mocks__/env';
import { CoreContext } from '../core_context';
import { configServiceMock } from '../config/config_service.mock';
-import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
-import { httpServiceMock } from '../http/http_service.mock';
import { loggingServiceMock } from '../logging/logging_service.mock';
+
import { PluginWrapper } from './plugin';
import { PluginName } from './types';
import { PluginsSystem } from './plugins_system';
-import { contextServiceMock } from '../context/context_service.mock';
+
+import { coreMock } from '../mocks';
const logger = loggingServiceMock.create();
function createPlugin(
@@ -68,11 +68,8 @@ const configService = configServiceMock.create();
configService.atPath.mockReturnValue(new BehaviorSubject({ initialize: true }));
let env: Env;
let coreContext: CoreContext;
-const setupDeps = {
- context: contextServiceMock.createSetupContract(),
- elasticsearch: elasticsearchServiceMock.createSetupContract(),
- http: httpServiceMock.createSetupContract(),
-};
+const setupDeps = coreMock.createInternalSetup();
+
beforeEach(() => {
env = Env.createDefault(getEnvOptions());
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index e7a4cdc0174b0..14943fc96f268 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -511,6 +511,8 @@ export interface CoreSetup {
elasticsearch: ElasticsearchServiceSetup;
// (undocumented)
http: HttpServiceSetup;
+ // (undocumented)
+ uiSettings: UiSettingsServiceSetup;
}
// @public
@@ -737,7 +739,7 @@ export interface InternalCoreStart {
// @internal (undocumented)
export interface InternalUiSettingsServiceSetup {
asScopedToClient(savedObjectsClient: SavedObjectsClientContract): IUiSettingsClient;
- setDefaults(values: Record): void;
+ register(settings: Record): void;
}
// @public
@@ -763,11 +765,8 @@ export type IScopedClusterClient = Pick(key: string) => Promise;
getAll: () => Promise>;
- getDefaults: () => Record;
- getUserProvided: () => Promise>;
+ getRegistered: () => Readonly>;
+ getUserProvided: () => Promise>>;
isOverridden: (key: string) => boolean;
remove: (key: string) => Promise;
removeMany: (keys: string[]) => Promise;
@@ -1074,6 +1073,9 @@ export interface RequestHandlerContext {
dataClient: IScopedClusterClient;
adminClient: IScopedClusterClient;
};
+ uiSettings: {
+ client: IUiSettingsClient;
+ };
};
}
@@ -1610,24 +1612,37 @@ export interface SessionStorageFactory {
// @public
export interface UiSettingsParams {
- category: string[];
- description: string;
- name: string;
+ category?: string[];
+ description?: string;
+ name?: string;
optionLabels?: Record;
options?: string[];
readonly?: boolean;
requiresPageReload?: boolean;
type?: UiSettingsType;
- value: SavedObjectAttribute;
+ value?: SavedObjectAttribute;
+}
+
+// @public (undocumented)
+export interface UiSettingsServiceSetup {
+ register(settings: Record): void;
}
// @public
export type UiSettingsType = 'json' | 'markdown' | 'number' | 'select' | 'boolean' | 'string';
+// @public
+export interface UserProvidedValues {
+ // (undocumented)
+ isOverridden?: boolean;
+ // (undocumented)
+ userValue?: T;
+}
+
// Warnings were encountered during analysis:
//
// src/core/server/http/router/response.ts:316:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts
-// src/core/server/plugins/plugins_service.ts:39:5 - (ae-forgotten-export) The symbol "DiscoveredPluginInternal" needs to be exported by the entry point index.d.ts
+// src/core/server/plugins/plugins_service.ts:38:5 - (ae-forgotten-export) The symbol "DiscoveredPluginInternal" needs to be exported by the entry point index.d.ts
```
diff --git a/src/core/server/server.ts b/src/core/server/server.ts
index 49136c8e09768..46974e204c7a4 100644
--- a/src/core/server/server.ts
+++ b/src/core/server/server.ts
@@ -21,7 +21,7 @@ import { take } from 'rxjs/operators';
import { Type } from '@kbn/config-schema';
import { ConfigService, Env, Config, ConfigPath } from './config';
-import { ElasticsearchService, ElasticsearchServiceSetup } from './elasticsearch';
+import { ElasticsearchService } from './elasticsearch';
import { HttpService, InternalHttpServiceSetup } from './http';
import { LegacyService } from './legacy';
import { Logger, LoggerFactory } from './logging';
@@ -39,7 +39,7 @@ import { config as uiSettingsConfig } from './ui_settings';
import { mapToObject } from '../utils/';
import { ContextService } from './context';
import { SavedObjectsServiceSetup } from './saved_objects/saved_objects_service';
-import { RequestHandlerContext } from '.';
+import { RequestHandlerContext, InternalCoreSetup } from '.';
const coreId = Symbol('core');
@@ -102,7 +102,7 @@ export class Server {
http: httpSetup,
});
- const coreSetup = {
+ const coreSetup: InternalCoreSetup = {
context: contextServiceSetup,
elasticsearch: elasticsearchServiceSetup,
http: httpSetup,
@@ -121,7 +121,7 @@ export class Server {
legacy: legacySetup,
});
- this.registerCoreContext({ ...coreSetup, savedObjects: savedObjectsSetup });
+ this.registerCoreContext(coreSetup, savedObjectsSetup);
return coreSetup;
}
@@ -163,27 +163,31 @@ export class Server {
);
}
- private registerCoreContext(coreSetup: {
- http: InternalHttpServiceSetup;
- elasticsearch: ElasticsearchServiceSetup;
- savedObjects: SavedObjectsServiceSetup;
- }) {
+ private registerCoreContext(
+ coreSetup: InternalCoreSetup,
+ savedObjects: SavedObjectsServiceSetup
+ ) {
coreSetup.http.registerRouteHandlerContext(
coreId,
'core',
async (context, req): Promise => {
const adminClient = await coreSetup.elasticsearch.adminClient$.pipe(take(1)).toPromise();
const dataClient = await coreSetup.elasticsearch.dataClient$.pipe(take(1)).toPromise();
+ const savedObjectsClient = savedObjects.clientProvider.getClient(req);
+
return {
savedObjects: {
// Note: the client provider doesn't support new ES clients
// emitted from adminClient$
- client: coreSetup.savedObjects.clientProvider.getClient(req),
+ client: savedObjectsClient,
},
elasticsearch: {
adminClient: adminClient.asScoped(req),
dataClient: dataClient.asScoped(req),
},
+ uiSettings: {
+ client: coreSetup.uiSettings.asScopedToClient(savedObjectsClient),
+ },
};
}
);
diff --git a/src/core/server/types.ts b/src/core/server/types.ts
index 46c70a91721b5..4878fb9ccae19 100644
--- a/src/core/server/types.ts
+++ b/src/core/server/types.ts
@@ -20,4 +20,5 @@
/** This module is intended for consumption by public to avoid import issues with server-side code */
export { PluginOpaqueId } from './plugins/types';
export * from './saved_objects/types';
+export * from './ui_settings/types';
export { EnvironmentMode, PackageInfo } from './config/types';
diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts
index 5f7e915365873..65b8792532acf 100644
--- a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts
+++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts
@@ -20,6 +20,8 @@
import sinon from 'sinon';
import Chance from 'chance';
+import { SavedObjectsErrorHelpers } from '../../saved_objects';
+
import { loggingServiceMock } from '../../logging/logging_service.mock';
import * as getUpgradeableConfigNS from './get_upgradeable_config';
import { createOrUpgradeSavedConfig } from './create_or_upgrade_saved_config';
@@ -50,6 +52,7 @@ describe('uiSettings/createOrUpgradeSavedConfig', function() {
version,
buildNum,
log: logger.get(),
+ handleWriteErrors: false,
...options,
});
@@ -173,85 +176,64 @@ describe('uiSettings/createOrUpgradeSavedConfig', function() {
});
});
- describe('onWriteError()', () => {
- it('is called with error and attributes when savedObjectsClient.create rejects', async () => {
- const { run, savedObjectsClient } = setup();
+ describe('handleWriteErrors', () => {
+ describe('handleWriteErrors: false', () => {
+ it('throws write errors', async () => {
+ const { run, savedObjectsClient } = setup();
+ const error = new Error('foo');
+ savedObjectsClient.create.callsFake(async () => {
+ throw error;
+ });
- const error = new Error('foo');
- savedObjectsClient.create.callsFake(async () => {
- throw error;
- });
-
- const onWriteError = sinon.stub();
- await run({ onWriteError });
- sinon.assert.calledOnce(onWriteError);
- sinon.assert.calledWithExactly(onWriteError, error, {
- buildNum,
+ await expect(run({ handleWriteErrors: false })).rejects.toThrowError(error);
});
});
+ describe('handleWriteErrors:true', () => {
+ it('returns undefined for ConflictError', async () => {
+ const { run, savedObjectsClient } = setup();
+ const error = new Error('foo');
+ savedObjectsClient.create.throws(SavedObjectsErrorHelpers.decorateConflictError(error));
- it('resolves with the return value of onWriteError()', async () => {
- const { run, savedObjectsClient } = setup();
-
- savedObjectsClient.create.callsFake(async () => {
- throw new Error('foo');
+ expect(await run({ handleWriteErrors: true })).toBe(undefined);
});
- const result = await run({ onWriteError: () => 123 });
- expect(result).toBe(123);
- });
-
- it('rejects with the error from onWriteError() if it rejects', async () => {
- const { run, savedObjectsClient } = setup();
+ it('returns config attributes for NotAuthorizedError', async () => {
+ const { run, savedObjectsClient } = setup();
+ const error = new Error('foo');
+ savedObjectsClient.create.throws(
+ SavedObjectsErrorHelpers.decorateNotAuthorizedError(error)
+ );
- savedObjectsClient.create.callsFake(async () => {
- throw new Error('foo');
+ expect(await run({ handleWriteErrors: true })).toEqual({
+ buildNum,
+ });
});
- try {
- await run({
- onWriteError: (error: Error) => Promise.reject(new Error(`${error.message} bar`)),
+ it('returns config attributes for ForbiddenError', async () => {
+ const { run, savedObjectsClient } = setup();
+ const error = new Error('foo');
+ savedObjectsClient.create.throws(SavedObjectsErrorHelpers.decorateForbiddenError(error));
+
+ expect(await run({ handleWriteErrors: true })).toEqual({
+ buildNum,
});
- throw new Error('expected run() to reject');
- } catch (error) {
- expect(error.message).toBe('foo bar');
- }
- });
+ });
- it('rejects with the error from onWriteError() if it throws sync', async () => {
- const { run, savedObjectsClient } = setup();
+ it('throws error for other SavedObjects exceptions', async () => {
+ const { run, savedObjectsClient } = setup();
+ const error = new Error('foo');
+ savedObjectsClient.create.throws(SavedObjectsErrorHelpers.decorateGeneralError(error));
- savedObjectsClient.create.callsFake(async () => {
- throw new Error('foo');
+ await expect(run({ handleWriteErrors: true })).rejects.toThrowError(error);
});
- try {
- await run({
- onWriteError: (error: Error) => {
- throw new Error(`${error.message} bar`);
- },
- });
- throw new Error('expected run() to reject');
- } catch (error) {
- expect(error.message).toBe('foo bar');
- }
- });
+ it('throws error for all other exceptions', async () => {
+ const { run, savedObjectsClient } = setup();
+ const error = new Error('foo');
+ savedObjectsClient.create.throws(error);
- it('rejects with the writeError if onWriteError() is undefined', async () => {
- const { run, savedObjectsClient } = setup();
-
- savedObjectsClient.create.callsFake(async () => {
- throw new Error('foo');
+ await expect(run({ handleWriteErrors: true })).rejects.toThrowError(error);
});
-
- try {
- await run({
- onWriteError: undefined,
- });
- throw new Error('expected run() to reject');
- } catch (error) {
- expect(error.message).toBe('foo');
- }
});
});
});
diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts
index 1655297adb6c9..809e15248b5b0 100644
--- a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts
+++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts
@@ -20,6 +20,7 @@
import { defaults } from 'lodash';
import { SavedObjectsClientContract, SavedObjectAttribute } from '../../saved_objects/types';
+import { SavedObjectsErrorHelpers } from '../../saved_objects/';
import { Logger } from '../../logging';
import { getUpgradeableConfig } from './get_upgradeable_config';
@@ -29,15 +30,13 @@ interface Options {
version: string;
buildNum: number;
log: Logger;
- onWriteError?: (
- error: Error,
- attributes: Record
- ) => Record | undefined;
+ handleWriteErrors: boolean;
}
+
export async function createOrUpgradeSavedConfig(
options: Options
): Promise | undefined> {
- const { savedObjectsClient, version, buildNum, log, onWriteError } = options;
+ const { savedObjectsClient, version, buildNum, log, handleWriteErrors } = options;
// try to find an older config we can upgrade
const upgradeableConfig = await getUpgradeableConfig({
@@ -52,8 +51,17 @@ export async function createOrUpgradeSavedConfig {
+ it('finds saved objects with type "config"', async () => {
+ const savedObjectsClient = savedObjectsClientMock.create();
+ savedObjectsClient.find.mockResolvedValue({
+ saved_objects: [{ id: '7.5.0' }],
+ } as any);
+
+ await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' });
+ expect(savedObjectsClient.find.mock.calls[0][0].type).toBe('config');
+ });
+
+ it('finds saved config with version < than Kibana version', async () => {
+ const savedConfig = { id: '7.4.0' };
+ const savedObjectsClient = savedObjectsClientMock.create();
+ savedObjectsClient.find.mockResolvedValue({
+ saved_objects: [savedConfig],
+ } as any);
+
+ const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' });
+ expect(result).toBe(savedConfig);
+ });
+
+ it('finds saved config with RC version === Kibana version', async () => {
+ const savedConfig = { id: '7.5.0-rc1' };
+ const savedObjectsClient = savedObjectsClientMock.create();
+ savedObjectsClient.find.mockResolvedValue({
+ saved_objects: [savedConfig],
+ } as any);
+
+ const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' });
+ expect(result).toBe(savedConfig);
+ });
+
+ it('does not find saved config with version === Kibana version', async () => {
+ const savedConfig = { id: '7.5.0' };
+ const savedObjectsClient = savedObjectsClientMock.create();
+ savedObjectsClient.find.mockResolvedValue({
+ saved_objects: [savedConfig],
+ } as any);
+
+ const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' });
+ expect(result).toBe(undefined);
+ });
+
+ it('does not find saved config with version > Kibana version', async () => {
+ const savedConfig = { id: '7.6.0' };
+ const savedObjectsClient = savedObjectsClientMock.create();
+ savedObjectsClient.find.mockResolvedValue({
+ saved_objects: [savedConfig],
+ } as any);
+
+ const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' });
+ expect(result).toBe(undefined);
+ });
+
+ it('handles empty config', async () => {
+ const savedObjectsClient = savedObjectsClientMock.create();
+ savedObjectsClient.find.mockResolvedValue({
+ saved_objects: [],
+ } as any);
+
+ const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' });
+ expect(result).toBe(undefined);
+ });
+});
diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts
index 83f8ce03299f6..9d52a339ccf91 100644
--- a/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts
+++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts
@@ -18,28 +18,31 @@
*/
import expect from '@kbn/expect';
-import { UnwrapPromise } from '@kbn/utility-types';
import { SavedObjectsClientContract } from 'src/core/server';
-import KbnServer from '../../../../../legacy/server/kbn_server';
-import { createTestServers } from '../../../../../test_utils/kbn_server';
+import {
+ createTestServers,
+ TestElasticsearchUtils,
+ TestKibanaUtils,
+ TestUtils,
+} from '../../../../../test_utils/kbn_server';
import { createOrUpgradeSavedConfig } from '../create_or_upgrade_saved_config';
import { loggingServiceMock } from '../../../logging/logging_service.mock';
const logger = loggingServiceMock.create().get();
describe('createOrUpgradeSavedConfig()', () => {
let savedObjectsClient: SavedObjectsClientContract;
- let kbnServer: KbnServer;
- let servers: ReturnType;
- let esServer: UnwrapPromise>;
- let kbn: UnwrapPromise>;
+ let servers: TestUtils;
+ let esServer: TestElasticsearchUtils;
+ let kbn: TestKibanaUtils;
+
+ let kbnServer: TestKibanaUtils['kbnServer'];
beforeAll(async function() {
servers = createTestServers({
adjustTimeout: t => {
jest.setTimeout(t);
},
- settings: {},
});
esServer = await servers.startES();
kbn = await servers.startKibana();
@@ -90,6 +93,7 @@ describe('createOrUpgradeSavedConfig()', () => {
version: '5.4.0',
buildNum: 54099,
log: logger,
+ handleWriteErrors: false,
});
const config540 = await savedObjectsClient.get('config', '5.4.0');
@@ -116,6 +120,7 @@ describe('createOrUpgradeSavedConfig()', () => {
version: '5.4.1',
buildNum: 54199,
log: logger,
+ handleWriteErrors: false,
});
const config541 = await savedObjectsClient.get('config', '5.4.1');
@@ -142,6 +147,7 @@ describe('createOrUpgradeSavedConfig()', () => {
version: '7.0.0-rc1',
buildNum: 70010,
log: logger,
+ handleWriteErrors: false,
});
const config700rc1 = await savedObjectsClient.get('config', '7.0.0-rc1');
@@ -169,6 +175,7 @@ describe('createOrUpgradeSavedConfig()', () => {
version: '7.0.0',
buildNum: 70099,
log: logger,
+ handleWriteErrors: false,
});
const config700 = await savedObjectsClient.get('config', '7.0.0');
@@ -197,6 +204,7 @@ describe('createOrUpgradeSavedConfig()', () => {
version: '6.2.3-rc1',
buildNum: 62310,
log: logger,
+ handleWriteErrors: false,
});
const config623rc1 = await savedObjectsClient.get('config', '6.2.3-rc1');
diff --git a/src/core/server/ui_settings/index.ts b/src/core/server/ui_settings/index.ts
index edd0bfc4f3a89..fd0a21bed4e12 100644
--- a/src/core/server/ui_settings/index.ts
+++ b/src/core/server/ui_settings/index.ts
@@ -17,16 +17,16 @@
* under the License.
*/
-export {
- IUiSettingsClient,
- UiSettingsClient,
- UiSettingsServiceOptions,
-} from './ui_settings_client';
+export { UiSettingsClient, UiSettingsServiceOptions } from './ui_settings_client';
export { config } from './ui_settings_config';
+export { UiSettingsService } from './ui_settings_service';
+
export {
+ UiSettingsServiceSetup,
+ IUiSettingsClient,
UiSettingsParams,
- UiSettingsService,
InternalUiSettingsServiceSetup,
UiSettingsType,
-} from './ui_settings_service';
+ UserProvidedValues,
+} from './types';
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/doc_exists.ts b/src/core/server/ui_settings/integration_tests/doc_exists.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/doc_exists.ts
rename to src/core/server/ui_settings/integration_tests/doc_exists.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/doc_missing.ts b/src/core/server/ui_settings/integration_tests/doc_missing.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/doc_missing.ts
rename to src/core/server/ui_settings/integration_tests/doc_missing.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/doc_missing_and_index_read_only.ts b/src/core/server/ui_settings/integration_tests/doc_missing_and_index_read_only.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/doc_missing_and_index_read_only.ts
rename to src/core/server/ui_settings/integration_tests/doc_missing_and_index_read_only.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/index.test.ts b/src/core/server/ui_settings/integration_tests/index.test.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/index.test.ts
rename to src/core/server/ui_settings/integration_tests/index.test.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/lib/assert.ts b/src/core/server/ui_settings/integration_tests/lib/assert.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/lib/assert.ts
rename to src/core/server/ui_settings/integration_tests/lib/assert.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/lib/chance.ts b/src/core/server/ui_settings/integration_tests/lib/chance.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/lib/chance.ts
rename to src/core/server/ui_settings/integration_tests/lib/chance.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/lib/index.ts b/src/core/server/ui_settings/integration_tests/lib/index.ts
similarity index 100%
rename from src/legacy/ui/ui_settings/routes/integration_tests/lib/index.ts
rename to src/core/server/ui_settings/integration_tests/lib/index.ts
diff --git a/src/legacy/ui/ui_settings/routes/integration_tests/lib/servers.ts b/src/core/server/ui_settings/integration_tests/lib/servers.ts
similarity index 83%
rename from src/legacy/ui/ui_settings/routes/integration_tests/lib/servers.ts
rename to src/core/server/ui_settings/integration_tests/lib/servers.ts
index ae0ef1c91411e..a1be1e7e7291e 100644
--- a/src/legacy/ui/ui_settings/routes/integration_tests/lib/servers.ts
+++ b/src/core/server/ui_settings/integration_tests/lib/servers.ts
@@ -17,20 +17,24 @@
* under the License.
*/
-import { UnwrapPromise } from '@kbn/utility-types';
import { SavedObjectsClientContract, IUiSettingsClient } from 'src/core/server';
-import KbnServer from '../../../../../server/kbn_server';
-import { createTestServers } from '../../../../../../test_utils/kbn_server';
-import { CallCluster } from '../../../../../../legacy/core_plugins/elasticsearch';
+import {
+ createTestServers,
+ TestElasticsearchUtils,
+ TestKibanaUtils,
+ TestUtils,
+} from '../../../../../test_utils/kbn_server';
+import { CallCluster } from '../../../../../legacy/core_plugins/elasticsearch';
-let kbnServer: KbnServer;
-let servers: ReturnType;
-let esServer: UnwrapPromise>;
-let kbn: UnwrapPromise>;
+let servers: TestUtils;
+let esServer: TestElasticsearchUtils;
+let kbn: TestKibanaUtils;
+
+let kbnServer: TestKibanaUtils['kbnServer'];
interface AllServices {
- kbnServer: KbnServer;
+ kbnServer: TestKibanaUtils['kbnServer'];
savedObjectsClient: SavedObjectsClientContract;
callCluster: CallCluster;
uiSettings: IUiSettingsClient;
diff --git a/src/core/server/ui_settings/routes/delete.ts b/src/core/server/ui_settings/routes/delete.ts
new file mode 100644
index 0000000000000..ee4c05325fcd4
--- /dev/null
+++ b/src/core/server/ui_settings/routes/delete.ts
@@ -0,0 +1,61 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { schema } from '@kbn/config-schema';
+
+import { IRouter } from '../../http';
+import { SavedObjectsErrorHelpers } from '../../saved_objects';
+import { CannotOverrideError } from '../ui_settings_errors';
+
+const validate = {
+ params: schema.object({
+ key: schema.string(),
+ }),
+};
+
+export function registerDeleteRoute(router: IRouter) {
+ router.delete(
+ { path: '/api/kibana/settings/{key}', validate },
+ async (context, request, response) => {
+ try {
+ const uiSettingsClient = context.core.uiSettings.client;
+
+ await uiSettingsClient.remove(request.params.key);
+
+ return response.ok({
+ body: {
+ settings: await uiSettingsClient.getUserProvided(),
+ },
+ });
+ } catch (error) {
+ if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
+ return response.customError({
+ body: error,
+ statusCode: error.output.statusCode,
+ });
+ }
+
+ if (error instanceof CannotOverrideError) {
+ return response.badRequest({ body: error });
+ }
+
+ throw error;
+ }
+ }
+ );
+}
diff --git a/src/core/server/ui_settings/routes/get.ts b/src/core/server/ui_settings/routes/get.ts
new file mode 100644
index 0000000000000..d249369a1ace7
--- /dev/null
+++ b/src/core/server/ui_settings/routes/get.ts
@@ -0,0 +1,45 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { IRouter } from '../../http';
+import { SavedObjectsErrorHelpers } from '../../saved_objects';
+
+export function registerGetRoute(router: IRouter) {
+ router.get(
+ { path: '/api/kibana/settings', validate: false },
+ async (context, request, response) => {
+ try {
+ const uiSettingsClient = context.core.uiSettings.client;
+ return response.ok({
+ body: {
+ settings: await uiSettingsClient.getUserProvided(),
+ },
+ });
+ } catch (error) {
+ if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
+ return response.customError({
+ body: error,
+ statusCode: error.output.statusCode,
+ });
+ }
+
+ throw error;
+ }
+ }
+ );
+}
diff --git a/src/core/server/ui_settings/routes/index.ts b/src/core/server/ui_settings/routes/index.ts
new file mode 100644
index 0000000000000..d70d55d725938
--- /dev/null
+++ b/src/core/server/ui_settings/routes/index.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 { IRouter } from 'src/core/server';
+
+import { registerDeleteRoute } from './delete';
+import { registerGetRoute } from './get';
+import { registerSetManyRoute } from './set_many';
+import { registerSetRoute } from './set';
+
+export function registerRoutes(router: IRouter) {
+ registerGetRoute(router);
+ registerDeleteRoute(router);
+ registerSetRoute(router);
+ registerSetManyRoute(router);
+}
diff --git a/src/core/server/ui_settings/routes/set.ts b/src/core/server/ui_settings/routes/set.ts
new file mode 100644
index 0000000000000..51ad256b51335
--- /dev/null
+++ b/src/core/server/ui_settings/routes/set.ts
@@ -0,0 +1,67 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { schema } from '@kbn/config-schema';
+
+import { IRouter } from '../../http';
+import { SavedObjectsErrorHelpers } from '../../saved_objects';
+import { CannotOverrideError } from '../ui_settings_errors';
+
+const validate = {
+ params: schema.object({
+ key: schema.string(),
+ }),
+ body: schema.object({
+ value: schema.any(),
+ }),
+};
+
+export function registerSetRoute(router: IRouter) {
+ router.post(
+ { path: '/api/kibana/settings/{key}', validate },
+ async (context, request, response) => {
+ try {
+ const uiSettingsClient = context.core.uiSettings.client;
+
+ const { key } = request.params;
+ const { value } = request.body;
+
+ await uiSettingsClient.set(key, value);
+
+ return response.ok({
+ body: {
+ settings: await uiSettingsClient.getUserProvided(),
+ },
+ });
+ } catch (error) {
+ if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
+ return response.customError({
+ body: error,
+ statusCode: error.output.statusCode,
+ });
+ }
+
+ if (error instanceof CannotOverrideError) {
+ return response.badRequest({ body: error });
+ }
+
+ throw error;
+ }
+ }
+ );
+}
diff --git a/src/core/server/ui_settings/routes/set_many.ts b/src/core/server/ui_settings/routes/set_many.ts
new file mode 100644
index 0000000000000..3794eba004bee
--- /dev/null
+++ b/src/core/server/ui_settings/routes/set_many.ts
@@ -0,0 +1,60 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { schema } from '@kbn/config-schema';
+
+import { IRouter } from '../../http';
+import { SavedObjectsErrorHelpers } from '../../saved_objects';
+import { CannotOverrideError } from '../ui_settings_errors';
+
+const validate = {
+ body: schema.object({
+ changes: schema.object({}, { allowUnknowns: true }),
+ }),
+};
+
+export function registerSetManyRoute(router: IRouter) {
+ router.post({ path: '/api/kibana/settings', validate }, async (context, request, response) => {
+ try {
+ const uiSettingsClient = context.core.uiSettings.client;
+
+ const { changes } = request.body;
+
+ await uiSettingsClient.setMany(changes);
+
+ return response.ok({
+ body: {
+ settings: await uiSettingsClient.getUserProvided(),
+ },
+ });
+ } catch (error) {
+ if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
+ return response.customError({
+ body: error,
+ statusCode: error.output.statusCode,
+ });
+ }
+
+ if (error instanceof CannotOverrideError) {
+ return response.badRequest({ body: error });
+ }
+
+ throw error;
+ }
+ });
+}
diff --git a/src/core/server/ui_settings/types.ts b/src/core/server/ui_settings/types.ts
new file mode 100644
index 0000000000000..0fa6b3702af24
--- /dev/null
+++ b/src/core/server/ui_settings/types.ts
@@ -0,0 +1,141 @@
+/*
+ * 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 { SavedObjectsClientContract, SavedObjectAttribute } from '../saved_objects/types';
+/**
+ * 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.
+ *
+ * @public
+ */
+export interface IUiSettingsClient {
+ /**
+ * Returns registered uiSettings values {@link UiSettingsParams}
+ */
+ getRegistered: () => Readonly>;
+ /**
+ * Retrieves uiSettings values set by the user with fallbacks to default values if not specified.
+ */
+ get: (key: string) => Promise;
+ /**
+ * Retrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified.
+ */
+ getAll: () => Promise>;
+ /**
+ * Retrieves a set of all uiSettings values set by the user.
+ */
+ getUserProvided: () => Promise<
+ Record>
+ >;
+ /**
+ * Writes multiple uiSettings values and marks them as set by the user.
+ */
+ setMany: (changes: Record) => Promise;
+ /**
+ * Writes uiSettings value and marks it as set by the user.
+ */
+ set: (key: string, value: T) => Promise;
+ /**
+ * Removes uiSettings value by key.
+ */
+ remove: (key: string) => Promise;
+ /**
+ * Removes multiple uiSettings values by keys.
+ */
+ removeMany: (keys: string[]) => Promise;
+ /**
+ * Shows whether the uiSettings value set by the user.
+ */
+ isOverridden: (key: string) => boolean;
+}
+
+/**
+ * Describes the values explicitly set by user.
+ * @public
+ * */
+export interface UserProvidedValues {
+ userValue?: T;
+ isOverridden?: boolean;
+}
+
+/**
+ * UI element type to represent the settings.
+ * @public
+ * */
+export type UiSettingsType = 'json' | 'markdown' | 'number' | 'select' | 'boolean' | 'string';
+
+/**
+ * UiSettings parameters defined by the plugins.
+ * @public
+ * */
+export interface UiSettingsParams {
+ /** title in the UI */
+ name?: string;
+ /** default value to fall back to if a user doesn't provide any */
+ value?: SavedObjectAttribute;
+ /** description provided to a user in UI */
+ description?: string;
+ /** used to group the configured setting in the UI */
+ category?: string[];
+ /** array of permitted values for this setting */
+ options?: string[];
+ /** text labels for 'select' type UI element */
+ optionLabels?: Record;
+ /** a flag indicating whether new value applying requires page reloading */
+ requiresPageReload?: boolean;
+ /** a flag indicating that value cannot be changed */
+ readonly?: boolean;
+ /** defines a type of UI element {@link UiSettingsType} */
+ type?: UiSettingsType;
+}
+
+/** @internal */
+export interface InternalUiSettingsServiceSetup {
+ /**
+ * Sets settings with default values for the uiSettings.
+ * @param settings
+ */
+ register(settings: Record): void;
+ /**
+ * Creates uiSettings client with provided *scoped* saved objects client {@link IUiSettingsClient}
+ * @param savedObjectsClient
+ */
+ asScopedToClient(savedObjectsClient: SavedObjectsClientContract): IUiSettingsClient;
+}
+
+/** @public */
+export interface UiSettingsServiceSetup {
+ /**
+ * Sets settings with default values for the uiSettings.
+ * @param settings
+ *
+ * @example
+ * setup(core: CoreSetup){
+ * core.uiSettings.register([{
+ * foo: {
+ * name: i18n.translate('my foo settings'),
+ * value: true,
+ * description: 'add some awesomeness',
+ * },
+ * }]);
+ * }
+ */
+ register(settings: Record): void;
+}
diff --git a/src/core/server/ui_settings/ui_settings_client.test.ts b/src/core/server/ui_settings/ui_settings_client.test.ts
index 59c13fbebee70..1c99637a89fed 100644
--- a/src/core/server/ui_settings/ui_settings_client.test.ts
+++ b/src/core/server/ui_settings/ui_settings_client.test.ts
@@ -24,6 +24,7 @@ import sinon from 'sinon';
import { loggingServiceMock } from '../logging/logging_service.mock';
import { UiSettingsClient } from './ui_settings_client';
+import { CannotOverrideError } from './ui_settings_errors';
import * as createOrUpgradeSavedConfigNS from './create_or_upgrade_saved_config/create_or_upgrade_saved_config';
import { createObjectsClientStub, savedObjectsClientErrors } from './create_objects_client_stub';
@@ -119,7 +120,12 @@ describe('ui settings', () => {
await uiSettings.setMany({ foo: 'bar' });
sinon.assert.calledTwice(savedObjectsClient.update);
+
sinon.assert.calledOnce(createOrUpgradeSavedConfig);
+ sinon.assert.calledWith(
+ createOrUpgradeSavedConfig,
+ sinon.match({ handleWriteErrors: false })
+ );
});
it('only tried to auto create once and throws NotFound', async () => {
@@ -135,9 +141,14 @@ describe('ui settings', () => {
sinon.assert.calledTwice(savedObjectsClient.update);
sinon.assert.calledOnce(createOrUpgradeSavedConfig);
+
+ sinon.assert.calledWith(
+ createOrUpgradeSavedConfig,
+ sinon.match({ handleWriteErrors: false })
+ );
});
- it('throws an error if any key is overridden', async () => {
+ it('throws CannotOverrideError if the key is overridden', async () => {
const { uiSettings } = setup({
overrides: {
foo: 'bar',
@@ -150,6 +161,7 @@ describe('ui settings', () => {
foo: 'baz',
});
} catch (error) {
+ expect(error).to.be.a(CannotOverrideError);
expect(error.message).to.be('Unable to update "foo" because it is overridden');
}
});
@@ -167,7 +179,7 @@ describe('ui settings', () => {
assertUpdateQuery({ one: 'value' });
});
- it('throws an error if the key is overridden', async () => {
+ it('throws CannotOverrideError if the key is overridden', async () => {
const { uiSettings } = setup({
overrides: {
foo: 'bar',
@@ -177,6 +189,7 @@ describe('ui settings', () => {
try {
await uiSettings.set('foo', 'baz');
} catch (error) {
+ expect(error).to.be.a(CannotOverrideError);
expect(error.message).to.be('Unable to update "foo" because it is overridden');
}
});
@@ -194,7 +207,7 @@ describe('ui settings', () => {
assertUpdateQuery({ one: null });
});
- it('throws an error if the key is overridden', async () => {
+ it('throws CannotOverrideError if the key is overridden', async () => {
const { uiSettings } = setup({
overrides: {
foo: 'bar',
@@ -204,6 +217,7 @@ describe('ui settings', () => {
try {
await uiSettings.remove('foo');
} catch (error) {
+ expect(error).to.be.a(CannotOverrideError);
expect(error.message).to.be('Unable to update "foo" because it is overridden');
}
});
@@ -227,7 +241,7 @@ describe('ui settings', () => {
assertUpdateQuery({ one: null, two: null, three: null });
});
- it('throws an error if any key is overridden', async () => {
+ it('throws CannotOverrideError if any key is overridden', async () => {
const { uiSettings } = setup({
overrides: {
foo: 'bar',
@@ -237,18 +251,18 @@ describe('ui settings', () => {
try {
await uiSettings.setMany({ baz: 'baz', foo: 'foo' });
} catch (error) {
+ expect(error).to.be.a(CannotOverrideError);
expect(error.message).to.be('Unable to update "foo" because it is overridden');
}
});
});
- describe('#getDefaults()', () => {
- it('returns the defaults passed to the constructor', () => {
+ describe('#getRegistered()', () => {
+ it('returns the registered settings passed to the constructor', () => {
const value = chance.word();
- const { uiSettings } = setup({ defaults: { key: { value } } });
- expect(uiSettings.getDefaults()).to.eql({
- key: { value },
- });
+ const defaults = { key: { value } };
+ const { uiSettings } = setup({ defaults });
+ expect(uiSettings.getRegistered()).to.be(defaults);
});
});
@@ -284,31 +298,48 @@ describe('ui settings', () => {
});
});
- it.skip('returns an empty object on NotFound responses', async () => {
- const { uiSettings, savedObjectsClient } = setup();
+ it('automatically creates the savedConfig if it is missing and returns empty object', async () => {
+ const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup();
+ savedObjectsClient.get
+ .onFirstCall()
+ .throws(savedObjectsClientErrors.createGenericNotFoundError())
+ .onSecondCall()
+ .returns({ attributes: {} });
- const error = savedObjectsClientErrors.createGenericNotFoundError();
- savedObjectsClient.get.throws(error);
+ expect(await uiSettings.getUserProvided()).to.eql({});
+
+ sinon.assert.calledTwice(savedObjectsClient.get);
+
+ sinon.assert.calledOnce(createOrUpgradeSavedConfig);
+ sinon.assert.calledWith(createOrUpgradeSavedConfig, sinon.match({ handleWriteErrors: true }));
+ });
- expect(await uiSettings.getUserProvided({})).to.eql({});
+ it('returns result of savedConfig creation in case of notFound error', async () => {
+ const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup();
+ createOrUpgradeSavedConfig.resolves({ foo: 'bar ' });
+ savedObjectsClient.get.throws(savedObjectsClientErrors.createGenericNotFoundError());
+
+ expect(await uiSettings.getUserProvided()).to.eql({ foo: { userValue: 'bar ' } });
});
it('returns an empty object on Forbidden responses', async () => {
- const { uiSettings, savedObjectsClient } = setup();
+ const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup();
const error = savedObjectsClientErrors.decorateForbiddenError(new Error());
savedObjectsClient.get.throws(error);
expect(await uiSettings.getUserProvided()).to.eql({});
+ sinon.assert.notCalled(createOrUpgradeSavedConfig);
});
it('returns an empty object on EsUnavailable responses', async () => {
- const { uiSettings, savedObjectsClient } = setup();
+ const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup();
const error = savedObjectsClientErrors.decorateEsUnavailableError(new Error());
savedObjectsClient.get.throws(error);
expect(await uiSettings.getUserProvided()).to.eql({});
+ sinon.assert.notCalled(createOrUpgradeSavedConfig);
});
it('throws Unauthorized errors', async () => {
@@ -346,6 +377,7 @@ describe('ui settings', () => {
const overrides = {
foo: 'bar',
+ baz: null,
};
const { uiSettings } = setup({ esDocSource, overrides });
@@ -357,57 +389,7 @@ describe('ui settings', () => {
userValue: 'bar',
isOverridden: true,
},
- });
- });
- });
-
- describe('#getRaw()', () => {
- it('pulls user configuration from ES', async () => {
- const esDocSource = {};
- const { uiSettings, assertGetQuery } = setup({ esDocSource });
- await uiSettings.getRaw();
- assertGetQuery();
- });
-
- it(`without user configuration it's equal to the defaults`, async () => {
- const esDocSource = {};
- const defaults = { key: { value: chance.word() } };
- const { uiSettings } = setup({ esDocSource, defaults });
- const result = await uiSettings.getRaw();
- expect(result).to.eql(defaults);
- });
-
- it(`user configuration gets merged with defaults`, async () => {
- const esDocSource = { foo: 'bar' };
- const defaults = { key: { value: chance.word() } };
- const { uiSettings } = setup({ esDocSource, defaults });
- const result = await uiSettings.getRaw();
-
- expect(result).to.eql({
- foo: {
- userValue: 'bar',
- },
- key: {
- value: defaults.key.value,
- },
- });
- });
-
- it('includes the values for overridden keys', async () => {
- const esDocSource = { foo: 'bar' };
- const defaults = { key: { value: chance.word() } };
- const overrides = { foo: true };
- const { uiSettings } = setup({ esDocSource, defaults, overrides });
- const result = await uiSettings.getRaw();
-
- expect(result).to.eql({
- foo: {
- userValue: true,
- isOverridden: true,
- },
- key: {
- value: defaults.key.value,
- },
+ baz: { isOverridden: true },
});
});
});
@@ -545,22 +527,4 @@ describe('ui settings', () => {
expect(uiSettings.isOverridden('bar')).to.be(true);
});
});
-
- describe('#assertUpdateAllowed()', () => {
- it('returns false if no overrides defined', () => {
- const { uiSettings } = setup();
- expect(uiSettings.assertUpdateAllowed('foo')).to.be(undefined);
- });
- it('throws 400 Boom error when keys is overridden', () => {
- const { uiSettings } = setup({ overrides: { foo: true } });
- expect(() => uiSettings.assertUpdateAllowed('foo')).to.throwError(error => {
- expect(error).to.have.property(
- 'message',
- 'Unable to update "foo" because it is overridden'
- );
- expect(error).to.have.property('isBoom', true);
- expect(error.output).to.have.property('statusCode', 400);
- });
- });
- });
});
diff --git a/src/core/server/ui_settings/ui_settings_client.ts b/src/core/server/ui_settings/ui_settings_client.ts
index c495d1b4c4567..423ff2a1dfd90 100644
--- a/src/core/server/ui_settings/ui_settings_client.ts
+++ b/src/core/server/ui_settings/ui_settings_client.ts
@@ -17,12 +17,13 @@
* under the License.
*/
import { defaultsDeep } from 'lodash';
-import Boom from 'boom';
+import { SavedObjectsErrorHelpers } from '../saved_objects';
import { SavedObjectsClientContract, SavedObjectAttribute } from '../saved_objects/types';
import { Logger } from '../logging';
import { createOrUpgradeSavedConfig } from './create_or_upgrade_saved_config';
-import { UiSettingsParams } from './ui_settings_service';
+import { IUiSettingsClient, UiSettingsParams } from './types';
+import { CannotOverrideError } from './ui_settings_errors';
export interface UiSettingsServiceOptions {
type: string;
@@ -49,52 +50,6 @@ type UiSettingsRawValue = UiSettingsParams & UserProvidedValue;
type UserProvided = Record>;
type UiSettingsRaw = Record;
-/**
- * Service that provides access to the UiSettings stored in elasticsearch.
- *
- * @public
- */
-export interface IUiSettingsClient {
- /**
- * Returns uiSettings default values {@link UiSettingsParams}
- */
- getDefaults: () => Record;
- /**
- * Retrieves uiSettings values set by the user with fallbacks to default values if not specified.
- */
- get: (key: string) => Promise;
- /**
- * Retrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified.
- */
- getAll: () => Promise>;
- /**
- * Retrieves a set of all uiSettings values set by the user.
- */
- getUserProvided: () => Promise<
- Record
- >;
- /**
- * Writes multiple uiSettings values and marks them as set by the user.
- */
- setMany: (changes: Record) => Promise;
- /**
- * Writes uiSettings value and marks it as set by the user.
- */
- set: (key: string, value: T) => Promise;
- /**
- * Removes uiSettings value by key.
- */
- remove: (key: string) => Promise;
- /**
- * Removes multiple uiSettings values by keys.
- */
- removeMany: (keys: string[]) => Promise;
- /**
- * Shows whether the uiSettings value set by the user.
- */
- isOverridden: (key: string) => boolean;
-}
-
export class UiSettingsClient implements IUiSettingsClient {
private readonly type: UiSettingsServiceOptions['type'];
private readonly id: UiSettingsServiceOptions['id'];
@@ -116,7 +71,7 @@ export class UiSettingsClient implements IUiSettingsClient {
this.log = log;
}
- getDefaults() {
+ getRegistered() {
return this.defaults;
}
@@ -138,19 +93,11 @@ export class UiSettingsClient implements IUiSettingsClient {
);
}
- // NOTE: should be a private method
- async getRaw(): Promise {
- const userProvided = await this.getUserProvided();
- return defaultsDeep(userProvided, this.defaults);
- }
-
- async getUserProvided(
- options: ReadOptions = {}
- ): Promise> {
+ async getUserProvided(): Promise> {
const userProvided: UserProvided = {};
// write the userValue for each key stored in the saved object that is not overridden
- for (const [key, userValue] of Object.entries(await this.read(options))) {
+ for (const [key, userValue] of Object.entries(await this.read())) {
if (userValue !== null && !this.isOverridden(key)) {
userProvided[key] = {
userValue,
@@ -192,13 +139,17 @@ export class UiSettingsClient implements IUiSettingsClient {
return this.overrides.hasOwnProperty(key);
}
- // NOTE: should be private method
- assertUpdateAllowed(key: string) {
+ private assertUpdateAllowed(key: string) {
if (this.isOverridden(key)) {
- throw Boom.badRequest(`Unable to update "${key}" because it is overridden`);
+ throw new CannotOverrideError(`Unable to update "${key}" because it is overridden`);
}
}
+ private async getRaw(): Promise {
+ const userProvided = await this.getUserProvided();
+ return defaultsDeep(userProvided, this.defaults);
+ }
+
private async write({
changes,
autoCreateOrUpgradeIfMissing = true,
@@ -213,8 +164,7 @@ export class UiSettingsClient implements IUiSettingsClient {
try {
await this.savedObjectsClient.update(this.type, this.id, changes);
} catch (error) {
- const { isNotFoundError } = this.savedObjectsClient.errors;
- if (!isNotFoundError(error) || !autoCreateOrUpgradeIfMissing) {
+ if (!SavedObjectsErrorHelpers.isNotFoundError(error) || !autoCreateOrUpgradeIfMissing) {
throw error;
}
@@ -223,6 +173,7 @@ export class UiSettingsClient implements IUiSettingsClient {
version: this.id,
buildNum: this.buildNum,
log: this.log,
+ handleWriteErrors: false,
});
await this.write({
@@ -236,37 +187,17 @@ export class UiSettingsClient implements IUiSettingsClient {
ignore401Errors = false,
autoCreateOrUpgradeIfMissing = true,
}: ReadOptions = {}): Promise> {
- const {
- isConflictError,
- isNotFoundError,
- isForbiddenError,
- isNotAuthorizedError,
- } = this.savedObjectsClient.errors;
-
try {
const resp = await this.savedObjectsClient.get(this.type, this.id);
return resp.attributes;
} catch (error) {
- if (isNotFoundError(error) && autoCreateOrUpgradeIfMissing) {
+ if (SavedObjectsErrorHelpers.isNotFoundError(error) && autoCreateOrUpgradeIfMissing) {
const failedUpgradeAttributes = await createOrUpgradeSavedConfig({
savedObjectsClient: this.savedObjectsClient,
version: this.id,
buildNum: this.buildNum,
log: this.log,
- onWriteError(writeError, attributes) {
- if (isConflictError(writeError)) {
- // trigger `!failedUpgradeAttributes` check below, since another
- // request caused the uiSettings object to be created so we can
- // just re-read
- return;
- }
-
- if (isNotAuthorizedError(writeError) || isForbiddenError(writeError)) {
- return attributes;
- }
-
- throw writeError;
- },
+ handleWriteErrors: true,
});
if (!failedUpgradeAttributes) {
diff --git a/src/core/server/ui_settings/ui_settings_errors.ts b/src/core/server/ui_settings/ui_settings_errors.ts
new file mode 100644
index 0000000000000..d8fc32b111e44
--- /dev/null
+++ b/src/core/server/ui_settings/ui_settings_errors.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 class CannotOverrideError extends Error {
+ public cause?: Error;
+
+ constructor(message: string, cause?: Error) {
+ super(message);
+ this.cause = cause;
+
+ // Set the prototype explicitly, see:
+ // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
+ Object.setPrototypeOf(this, CannotOverrideError.prototype);
+ }
+}
diff --git a/src/core/server/ui_settings/ui_settings_service.mock.ts b/src/core/server/ui_settings/ui_settings_service.mock.ts
index 2127faf0d2029..bb21109a2f967 100644
--- a/src/core/server/ui_settings/ui_settings_service.mock.ts
+++ b/src/core/server/ui_settings/ui_settings_service.mock.ts
@@ -17,12 +17,11 @@
* under the License.
*/
-import { IUiSettingsClient } from './ui_settings_client';
-import { InternalUiSettingsServiceSetup } from './ui_settings_service';
+import { IUiSettingsClient, InternalUiSettingsServiceSetup } from './types';
const createClientMock = () => {
const mocked: jest.Mocked = {
- getDefaults: jest.fn(),
+ getRegistered: jest.fn(),
get: jest.fn(),
getAll: jest.fn(),
getUserProvided: jest.fn(),
@@ -38,7 +37,7 @@ const createClientMock = () => {
const createSetupMock = () => {
const mocked: jest.Mocked = {
- setDefaults: jest.fn(),
+ register: jest.fn(),
asScopedToClient: jest.fn(),
};
@@ -48,6 +47,6 @@ const createSetupMock = () => {
};
export const uiSettingsServiceMock = {
- createSetup: createSetupMock,
+ createSetupContract: createSetupMock,
createClient: createClientMock,
};
diff --git a/src/core/server/ui_settings/ui_settings_service.test.ts b/src/core/server/ui_settings/ui_settings_service.test.ts
index e219d0c962344..d7a085a220190 100644
--- a/src/core/server/ui_settings/ui_settings_service.test.ts
+++ b/src/core/server/ui_settings/ui_settings_service.test.ts
@@ -52,6 +52,14 @@ afterEach(() => {
describe('uiSettings', () => {
describe('#setup', () => {
describe('#asScopedToClient', () => {
+ it('passes saved object type "config" to UiSettingsClient', async () => {
+ const service = new UiSettingsService(coreContext);
+ const setup = await service.setup(setupDeps);
+ setup.asScopedToClient(savedObjectsClient);
+ expect(MockUiSettingsClientConstructor).toBeCalledTimes(1);
+ expect(MockUiSettingsClientConstructor.mock.calls[0][0].type).toBe('config');
+ });
+
it('passes overrides to UiSettingsClient', async () => {
const service = new UiSettingsService(coreContext);
const setup = await service.setup(setupDeps);
@@ -86,7 +94,7 @@ describe('uiSettings', () => {
const service = new UiSettingsService(coreContext);
const setup = await service.setup(setupDeps);
- setup.setDefaults(defaults);
+ setup.register(defaults);
setup.asScopedToClient(savedObjectsClient);
expect(MockUiSettingsClientConstructor).toBeCalledTimes(1);
@@ -95,13 +103,13 @@ describe('uiSettings', () => {
});
});
- describe('#setDefaults', () => {
- it('throws if set defaults for the same key twice', async () => {
+ describe('#register', () => {
+ it('throws if registers the same key twice', async () => {
const service = new UiSettingsService(coreContext);
const setup = await service.setup(setupDeps);
- setup.setDefaults(defaults);
- expect(() => setup.setDefaults(defaults)).toThrowErrorMatchingInlineSnapshot(
- `"uiSettings defaults for key [foo] has been already set"`
+ setup.register(defaults);
+ expect(() => setup.register(defaults)).toThrowErrorMatchingInlineSnapshot(
+ `"uiSettings for the key [foo] has been already registered"`
);
});
});
diff --git a/src/core/server/ui_settings/ui_settings_service.ts b/src/core/server/ui_settings/ui_settings_service.ts
index 746fa514c5d4b..a8f5663f8bd1e 100644
--- a/src/core/server/ui_settings/ui_settings_service.ts
+++ b/src/core/server/ui_settings/ui_settings_service.ts
@@ -26,58 +26,16 @@ import { Logger } from '../logging';
import { SavedObjectsClientContract, SavedObjectAttribute } from '../saved_objects/types';
import { InternalHttpServiceSetup } from '../http';
import { UiSettingsConfigType } from './ui_settings_config';
-import { IUiSettingsClient, UiSettingsClient } from './ui_settings_client';
+import { UiSettingsClient } from './ui_settings_client';
+import { InternalUiSettingsServiceSetup, UiSettingsParams } from './types';
import { mapToObject } from '../../utils/';
+import { registerRoutes } from './routes';
+
interface SetupDeps {
http: InternalHttpServiceSetup;
}
-/**
- * UI element type to represent the settings.
- * @public
- * */
-export type UiSettingsType = 'json' | 'markdown' | 'number' | 'select' | 'boolean' | 'string';
-
-/**
- * UiSettings parameters defined by the plugins.
- * @public
- * */
-export interface UiSettingsParams {
- /** title in the UI */
- name: string;
- /** default value to fall back to if a user doesn't provide any */
- value: SavedObjectAttribute;
- /** description provided to a user in UI */
- description: string;
- /** used to group the configured setting in the UI */
- category: string[];
- /** a range of valid values */
- options?: string[];
- /** text labels for 'select' type UI element */
- optionLabels?: Record;
- /** a flag indicating whether new value applying requires page reloading */
- requiresPageReload?: boolean;
- /** a flag indicating that value cannot be changed */
- readonly?: boolean;
- /** defines a type of UI element {@link UiSettingsType} */
- type?: UiSettingsType;
-}
-
-/** @internal */
-export interface InternalUiSettingsServiceSetup {
- /**
- * Sets the parameters with default values for the uiSettings.
- * @param values
- */
- setDefaults(values: Record): void;
- /**
- * Creates uiSettings client with provided *scoped* saved objects client {@link IUiSettingsClient}
- * @param values
- */
- asScopedToClient(savedObjectsClient: SavedObjectsClientContract): IUiSettingsClient;
-}
-
/** @internal */
export class UiSettingsService implements CoreService {
private readonly log: Logger;
@@ -90,12 +48,13 @@ export class UiSettingsService implements CoreService {
+ registerRoutes(deps.http.createRouter(''));
this.log.debug('Setting up ui settings service');
const overrides = await this.getOverrides(deps);
const { version, buildNum } = this.coreContext.env.packageInfo;
return {
- setDefaults: this.setDefaults.bind(this),
+ register: this.register.bind(this),
asScopedToClient: (savedObjectsClient: SavedObjectsClientContract) => {
return new UiSettingsClient({
type: 'config',
@@ -114,10 +73,10 @@ export class UiSettingsService implements CoreService = {}) {
- Object.entries(values).forEach(([key, value]) => {
+ private register(settings: Record = {}) {
+ Object.entries(settings).forEach(([key, value]) => {
if (this.uiSettingsDefaults.has(key)) {
- throw new Error(`uiSettings defaults for key [${key}] has been already set`);
+ throw new Error(`uiSettings for the key [${key}] has been already registered`);
}
this.uiSettingsDefaults.set(key, value);
});
diff --git a/src/legacy/server/http/integration_tests/default_route_provider.test.ts b/src/legacy/server/http/integration_tests/default_route_provider.test.ts
index d74be851a3535..4898cb2b67852 100644
--- a/src/legacy/server/http/integration_tests/default_route_provider.test.ts
+++ b/src/legacy/server/http/integration_tests/default_route_provider.test.ts
@@ -44,7 +44,7 @@ describe('default route provider', () => {
}
throw Error(`unsupported ui setting: ${key}`);
},
- getDefaults: () => {
+ getRegistered: () => {
return {
defaultRoute: {
value: '/app/kibana',
diff --git a/src/legacy/server/http/setup_default_route_provider.ts b/src/legacy/server/http/setup_default_route_provider.ts
index f627cf30a3cff..0e7bcf1f56f6f 100644
--- a/src/legacy/server/http/setup_default_route_provider.ts
+++ b/src/legacy/server/http/setup_default_route_provider.ts
@@ -40,7 +40,7 @@ export function setupDefaultRouteProvider(server: Legacy.Server) {
`Ignoring configured default route of '${defaultRoute}', as it is malformed.`
);
- const fallbackRoute = uiSettings.getDefaults().defaultRoute.value;
+ const fallbackRoute = uiSettings.getRegistered().defaultRoute.value;
const qualifiedFallbackRoute = `${request.getBasePath()}${fallbackRoute}`;
return qualifiedFallbackRoute;
diff --git a/src/legacy/ui/__tests__/ui_exports_replace_injected_vars.js b/src/legacy/ui/__tests__/ui_exports_replace_injected_vars.js
index 20ff1d5bcfe0a..a58ec992495fd 100644
--- a/src/legacy/ui/__tests__/ui_exports_replace_injected_vars.js
+++ b/src/legacy/ui/__tests__/ui_exports_replace_injected_vars.js
@@ -69,7 +69,7 @@ describe('UiExports', function () {
sandbox
.stub(getUiSettingsServiceForRequestNS, 'getUiSettingsServiceForRequest')
.returns({
- getDefaults: noop,
+ getRegistered: noop,
getUserProvided: noop
});
});
diff --git a/src/legacy/ui/field_formats/mixin/field_formats_mixin.ts b/src/legacy/ui/field_formats/mixin/field_formats_mixin.ts
index 27b3967d6f46e..66466b96abe83 100644
--- a/src/legacy/ui/field_formats/mixin/field_formats_mixin.ts
+++ b/src/legacy/ui/field_formats/mixin/field_formats_mixin.ts
@@ -28,9 +28,9 @@ export function fieldFormatsMixin(kbnServer: any, server: Legacy.Server) {
// for use outside of the request context, for special cases
server.decorate('server', 'fieldFormatServiceFactory', async function(uiSettings) {
const uiConfigs = await uiSettings.getAll();
- const uiSettingDefaults = uiSettings.getDefaults();
- Object.keys(uiSettingDefaults).forEach(key => {
- if (has(uiConfigs, key) && uiSettingDefaults[key].type === 'json') {
+ const registeredUiSettings = uiSettings.getRegistered();
+ Object.keys(registeredUiSettings).forEach(key => {
+ if (has(uiConfigs, key) && registeredUiSettings[key].type === 'json') {
uiConfigs[key] = JSON.parse(uiConfigs[key]);
}
});
diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js
index 883358e0d3c9a..0d05ea259d1a1 100644
--- a/src/legacy/ui/ui_render/ui_render_mixin.js
+++ b/src/legacy/ui/ui_render/ui_render_mixin.js
@@ -185,7 +185,7 @@ export function uiRenderMixin(kbnServer, server, config) {
async function getUiSettings({ request, includeUserProvidedConfig }) {
const uiSettings = request.getUiSettingsService();
return props({
- defaults: uiSettings.getDefaults(),
+ defaults: uiSettings.getRegistered(),
user: includeUserProvidedConfig && uiSettings.getUserProvided()
});
}
diff --git a/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts b/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts
index 3da7f83be4894..dd3f12903abca 100644
--- a/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts
+++ b/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts
@@ -73,7 +73,7 @@ describe('uiSettingsMixin()', () => {
newPlatform: {
__internals: {
uiSettings: {
- setDefaults: sinon.stub(),
+ register: sinon.stub(),
},
},
},
@@ -93,9 +93,9 @@ describe('uiSettingsMixin()', () => {
it('passes uiSettingsDefaults to the new platform', () => {
const { kbnServer } = setup();
- sinon.assert.calledOnce(kbnServer.newPlatform.__internals.uiSettings.setDefaults);
+ sinon.assert.calledOnce(kbnServer.newPlatform.__internals.uiSettings.register);
sinon.assert.calledWithExactly(
- kbnServer.newPlatform.__internals.uiSettings.setDefaults,
+ kbnServer.newPlatform.__internals.uiSettings.register,
uiSettingDefaults
);
});
diff --git a/src/legacy/ui/ui_settings/routes/set.ts b/src/legacy/ui/ui_settings/routes/set.ts
deleted file mode 100644
index 1f1ab17a0daf7..0000000000000
--- a/src/legacy/ui/ui_settings/routes/set.ts
+++ /dev/null
@@ -1,55 +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 { Legacy } from 'kibana';
-import Joi from 'joi';
-
-async function handleRequest(request: Legacy.Request) {
- const { key } = request.params;
- const { value } = request.payload as any;
- const uiSettings = request.getUiSettingsService();
-
- await uiSettings.set(key, value);
-
- return {
- settings: await uiSettings.getUserProvided(),
- };
-}
-
-export const setRoute = {
- path: '/api/kibana/settings/{key}',
- method: 'POST',
- config: {
- validate: {
- params: Joi.object()
- .keys({
- key: Joi.string().required(),
- })
- .default(),
-
- payload: Joi.object()
- .keys({
- value: Joi.any().required(),
- })
- .required(),
- },
- handler(request: Legacy.Request) {
- return handleRequest(request);
- },
- },
-};
diff --git a/src/legacy/ui/ui_settings/ui_settings_mixin.js b/src/legacy/ui/ui_settings/ui_settings_mixin.js
index 8c7ef25c6f8d7..64251d290776c 100644
--- a/src/legacy/ui/ui_settings/ui_settings_mixin.js
+++ b/src/legacy/ui/ui_settings/ui_settings_mixin.js
@@ -19,12 +19,6 @@
import { uiSettingsServiceFactory } from './ui_settings_service_factory';
import { getUiSettingsServiceForRequest } from './ui_settings_service_for_request';
-import {
- deleteRoute,
- getRoute,
- setManyRoute,
- setRoute,
-} from './routes';
export function uiSettingsMixin(kbnServer, server) {
const { uiSettingDefaults = {} } = kbnServer.uiExports;
@@ -43,7 +37,7 @@ export function uiSettingsMixin(kbnServer, server) {
return acc;
}, {});
- kbnServer.newPlatform.__internals.uiSettings.setDefaults(mergedUiSettingDefaults);
+ kbnServer.newPlatform.__internals.uiSettings.register(mergedUiSettingDefaults);
server.decorate('server', 'uiSettingsServiceFactory', (options = {}) => {
return uiSettingsServiceFactory(server, options);
@@ -58,9 +52,4 @@ export function uiSettingsMixin(kbnServer, server) {
server.uiSettings has been removed, see https://github.com/elastic/kibana/pull/12243.
`);
});
-
- server.route(deleteRoute);
- server.route(getRoute);
- server.route(setManyRoute);
- server.route(setRoute);
}
diff --git a/src/test_utils/kbn_server.ts b/src/test_utils/kbn_server.ts
index 52e2b869d5639..1494c01166e20 100644
--- a/src/test_utils/kbn_server.ts
+++ b/src/test_utils/kbn_server.ts
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-
+import { Client } from 'elasticsearch';
import { ToolingLog } from '@kbn/dev-utils';
import {
createLegacyEsTestCluster,
@@ -36,6 +36,7 @@ import { CliArgs, Env } from '../core/server/config';
import { LegacyObjectToConfigAdapter } from '../core/server/legacy';
import { Root } from '../core/server/root';
import KbnServer from '../legacy/server/kbn_server';
+import { CallCluster } from '../legacy/core_plugins/elasticsearch';
type HttpMethod = 'delete' | 'get' | 'head' | 'post' | 'put';
@@ -147,6 +148,35 @@ export const request: Record<
put: (root, path) => getSupertest(root, 'put', path),
};
+export interface TestElasticsearchServer {
+ getStartTimeout: () => number;
+ start: (esArgs: string[], esEnvVars: Record) => Promise;
+ stop: () => Promise;
+ cleanup: () => Promise;
+ getClient: () => Client;
+ getCallCluster: () => CallCluster;
+ getUrl: () => string;
+}
+
+export interface TestElasticsearchUtils {
+ stop: () => Promise;
+ es: TestElasticsearchServer;
+ hosts: string[];
+ username: string;
+ password: string;
+}
+
+export interface TestKibanaUtils {
+ root: Root;
+ kbnServer: KbnServer;
+ stop: () => Promise;
+}
+
+export interface TestUtils {
+ startES: () => Promise;
+ startKibana: () => Promise;
+}
+
/**
* Creates an instance of the Root, including all of the core "legacy" plugins,
* with default configuration tailored for unit tests, and starts es.
@@ -161,7 +191,7 @@ export function createTestServers({
settings = {},
}: {
adjustTimeout: (timeout: number) => void;
- settings: {
+ settings?: {
es?: {
license: 'oss' | 'basic' | 'gold' | 'trial';
[key: string]: any;
@@ -182,7 +212,7 @@ export function createTestServers({
*/
users?: Array<{ username: string; password: string; roles: string[] }>;
};
-}) {
+}): TestUtils {
if (!adjustTimeout) {
throw new Error('adjustTimeout is required in order to avoid flaky tests');
}
diff --git a/test/plugin_functional/plugins/core_plugin_b/server/plugin.ts b/test/plugin_functional/plugins/core_plugin_b/server/plugin.ts
index 67c9120b1f2d9..771e50b22f66b 100644
--- a/test/plugin_functional/plugins/core_plugin_b/server/plugin.ts
+++ b/test/plugin_functional/plugins/core_plugin_b/server/plugin.ts
@@ -29,7 +29,7 @@ declare module 'kibana/server' {
export class CorePluginBPlugin implements Plugin {
public setup(core: CoreSetup, deps: {}) {
const router = core.http.createRouter();
- router.get({ path: '/core_plugin_b/', validate: false }, async (context, req, res) => {
+ router.get({ path: '/core_plugin_b', validate: false }, async (context, req, res) => {
if (!context.pluginA) return res.internalError({ body: 'pluginA is disabled' });
const response = await context.pluginA.ping();
return res.ok({ body: `Pong via plugin A: ${response}` });
diff --git a/test/plugin_functional/plugins/ui_settings_plugin/kibana.json b/test/plugin_functional/plugins/ui_settings_plugin/kibana.json
new file mode 100644
index 0000000000000..05d2dca0af937
--- /dev/null
+++ b/test/plugin_functional/plugins/ui_settings_plugin/kibana.json
@@ -0,0 +1,8 @@
+{
+ "id": "ui_settings_plugin",
+ "version": "0.0.1",
+ "kibanaVersion": "kibana",
+ "configPath": ["ui_settings_plugin"],
+ "server": true,
+ "ui": true
+}
diff --git a/test/plugin_functional/plugins/ui_settings_plugin/package.json b/test/plugin_functional/plugins/ui_settings_plugin/package.json
new file mode 100644
index 0000000000000..6a0d5999412ff
--- /dev/null
+++ b/test/plugin_functional/plugins/ui_settings_plugin/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "ui_settings_plugin",
+ "version": "1.0.0",
+ "main": "target/test/plugin_functional/plugins/ui_settings_plugin",
+ "kibana": {
+ "version": "kibana",
+ "templateVersion": "1.0.0"
+ },
+ "license": "Apache-2.0",
+ "scripts": {
+ "kbn": "node ../../../../scripts/kbn.js",
+ "build": "rm -rf './target' && tsc"
+ },
+ "devDependencies": {
+ "typescript": "3.5.3"
+ }
+}
diff --git a/src/legacy/ui/ui_settings/routes/index.ts b/test/plugin_functional/plugins/ui_settings_plugin/public/index.ts
similarity index 84%
rename from src/legacy/ui/ui_settings/routes/index.ts
rename to test/plugin_functional/plugins/ui_settings_plugin/public/index.ts
index f3c9d4f0d8d14..3c5997132d460 100644
--- a/src/legacy/ui/ui_settings/routes/index.ts
+++ b/test/plugin_functional/plugins/ui_settings_plugin/public/index.ts
@@ -16,8 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { UiSettingsPlugin } from './plugin';
-export { deleteRoute } from './delete';
-export { getRoute } from './get';
-export { setManyRoute } from './set_many';
-export { setRoute } from './set';
+export const plugin = () => new UiSettingsPlugin();
diff --git a/src/legacy/ui/ui_settings/routes/delete.ts b/test/plugin_functional/plugins/ui_settings_plugin/public/plugin.tsx
similarity index 63%
rename from src/legacy/ui/ui_settings/routes/delete.ts
rename to test/plugin_functional/plugins/ui_settings_plugin/public/plugin.tsx
index 7825204e6b99b..883d203b4c37a 100644
--- a/src/legacy/ui/ui_settings/routes/delete.ts
+++ b/test/plugin_functional/plugins/ui_settings_plugin/public/plugin.tsx
@@ -16,22 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Legacy } from 'kibana';
-async function handleRequest(request: Legacy.Request) {
- const { key } = request.params;
- const uiSettings = request.getUiSettingsService();
+import { CoreSetup, Plugin } from 'kibana/public';
- await uiSettings.remove(key);
- return {
- settings: await uiSettings.getUserProvided(),
- };
+declare global {
+ interface Window {
+ uiSettingsPlugin?: Record;
+ uiSettingsPluginValue?: string;
+ }
}
-export const deleteRoute = {
- path: '/api/kibana/settings/{key}',
- method: 'DELETE',
- handler: async (request: Legacy.Request) => {
- return await handleRequest(request);
- },
-};
+export class UiSettingsPlugin implements Plugin {
+ public setup(core: CoreSetup) {
+ window.uiSettingsPlugin = core.uiSettings.getAll().ui_settings_plugin;
+ window.uiSettingsPluginValue = core.uiSettings.get('ui_settings_plugin');
+ }
+
+ public start() {}
+ public stop() {}
+}
diff --git a/test/plugin_functional/services/index.js b/test/plugin_functional/plugins/ui_settings_plugin/server/index.ts
similarity index 86%
rename from test/plugin_functional/services/index.js
rename to test/plugin_functional/plugins/ui_settings_plugin/server/index.ts
index bf02587772f4b..7715cef31d72c 100644
--- a/test/plugin_functional/services/index.js
+++ b/test/plugin_functional/plugins/ui_settings_plugin/server/index.ts
@@ -17,8 +17,6 @@
* under the License.
*/
-import { KibanaSupertestProvider } from './supertest';
+import { UiSettingsPlugin } from './plugin';
-export const services = {
- supertest: KibanaSupertestProvider,
-};
+export const plugin = () => new UiSettingsPlugin();
diff --git a/src/legacy/ui/ui_settings/routes/set_many.ts b/test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts
similarity index 53%
rename from src/legacy/ui/ui_settings/routes/set_many.ts
rename to test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts
index 18b1046417fec..c32e8a75d95da 100644
--- a/src/legacy/ui/ui_settings/routes/set_many.ts
+++ b/test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts
@@ -16,35 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Legacy } from 'kibana';
-import Joi from 'joi';
-async function handleRequest(request: Legacy.Request) {
- const { changes } = request.payload as any;
- const uiSettings = request.getUiSettingsService();
+import { Plugin, CoreSetup } from 'kibana/server';
- await uiSettings.setMany(changes);
+export class UiSettingsPlugin implements Plugin {
+ public setup(core: CoreSetup) {
+ core.uiSettings.register({
+ ui_settings_plugin: {
+ name: 'from_ui_settings_plugin',
+ description: 'just for testing',
+ value: '2',
+ category: ['any'],
+ },
+ });
- return {
- settings: await uiSettings.getUserProvided(),
- };
-}
+ const router = core.http.createRouter();
+ router.get({ path: '/api/ui-settings-plugin', validate: false }, async (context, req, res) => {
+ const uiSettingsValue = await context.core.uiSettings.client.get(
+ 'ui_settings_plugin'
+ );
+ return res.ok({ body: { uiSettingsValue } });
+ });
+ }
-export const setManyRoute = {
- path: '/api/kibana/settings',
- method: 'POST',
- config: {
- validate: {
- payload: Joi.object()
- .keys({
- changes: Joi.object()
- .unknown(true)
- .required(),
- })
- .required(),
- },
- handler(request: Legacy.Request) {
- return handleRequest(request);
- },
- },
-};
+ public start() {}
+ public stop() {}
+}
diff --git a/test/plugin_functional/plugins/ui_settings_plugin/tsconfig.json b/test/plugin_functional/plugins/ui_settings_plugin/tsconfig.json
new file mode 100644
index 0000000000000..1ba21f11b7de2
--- /dev/null
+++ b/test/plugin_functional/plugins/ui_settings_plugin/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./target",
+ "skipLibCheck": true
+ },
+ "include": [
+ "index.ts",
+ "public/**/*.ts",
+ "public/**/*.tsx",
+ "server/**/*.ts",
+ "../../../../typings/**/*",
+ ],
+ "exclude": []
+}
diff --git a/src/legacy/ui/ui_settings/routes/get.ts b/test/plugin_functional/services/index.ts
similarity index 68%
rename from src/legacy/ui/ui_settings/routes/get.ts
rename to test/plugin_functional/services/index.ts
index 3e165a12522bb..dd2b25e14fe17 100644
--- a/src/legacy/ui/ui_settings/routes/get.ts
+++ b/test/plugin_functional/services/index.ts
@@ -16,19 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Legacy } from 'kibana';
+import { GenericFtrProviderContext } from '@kbn/test/types/ftr';
+import { FtrProviderContext } from 'test/functional/ftr_provider_context';
-async function handleRequest(request: Legacy.Request) {
- const uiSettings = request.getUiSettingsService();
- return {
- settings: await uiSettings.getUserProvided(),
- };
-}
+import { KibanaSupertestProvider } from './supertest';
-export const getRoute = {
- path: '/api/kibana/settings',
- method: 'GET',
- handler(request: Legacy.Request) {
- return handleRequest(request);
- },
+export const services = {
+ supertest: KibanaSupertestProvider,
};
+
+export type PluginFunctionalProviderContext = FtrProviderContext &
+ GenericFtrProviderContext;
diff --git a/test/plugin_functional/services/supertest.js b/test/plugin_functional/services/supertest.ts
similarity index 87%
rename from test/plugin_functional/services/supertest.js
rename to test/plugin_functional/services/supertest.ts
index 390f89acaa775..6b7dc26248c06 100644
--- a/test/plugin_functional/services/supertest.js
+++ b/test/plugin_functional/services/supertest.ts
@@ -16,13 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-
-
import { format as formatUrl } from 'url';
+import { FtrProviderContext } from 'test/functional/ftr_provider_context';
import supertestAsPromised from 'supertest-as-promised';
-export function KibanaSupertestProvider({ getService }) {
+export function KibanaSupertestProvider({ getService }: FtrProviderContext) {
const config = getService('config');
const kibanaServerUrl = formatUrl(config.get('servers.kibana'));
return supertestAsPromised(kibanaServerUrl);
diff --git a/test/plugin_functional/test_suites/core_plugins/applications.js b/test/plugin_functional/test_suites/core_plugins/applications.ts
similarity index 86%
rename from test/plugin_functional/test_suites/core_plugins/applications.js
rename to test/plugin_functional/test_suites/core_plugins/applications.ts
index 4c4c198d1af94..eec2ec019a515 100644
--- a/test/plugin_functional/test_suites/core_plugins/applications.js
+++ b/test/plugin_functional/test_suites/core_plugins/applications.ts
@@ -18,8 +18,10 @@
*/
import url from 'url';
import expect from '@kbn/expect';
+import { PluginFunctionalProviderContext } from '../../services';
-export default function ({ getService, getPageObjects }) {
+// eslint-disable-next-line import/no-default-export
+export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
const PageObjects = getPageObjects(['common']);
const browser = getService('browser');
@@ -29,16 +31,16 @@ export default function ({ getService, getPageObjects }) {
const loadingScreenNotShown = async () =>
expect(await testSubjects.exists('kbnLoadingMessage')).to.be(false);
- const loadingScreenShown = () =>
- testSubjects.existOrFail('kbnLoadingMessage');
+ const loadingScreenShown = () => testSubjects.existOrFail('kbnLoadingMessage');
- const getKibanaUrl = (pathname, search) => url.format({
- protocol: 'http:',
- hostname: process.env.TEST_KIBANA_HOST || 'localhost',
- port: process.env.TEST_KIBANA_PORT || '5620',
- pathname,
- search,
- });
+ const getKibanaUrl = (pathname?: string, search?: string) =>
+ url.format({
+ protocol: 'http:',
+ hostname: process.env.TEST_KIBANA_HOST || 'localhost',
+ port: process.env.TEST_KIBANA_PORT || '5620',
+ pathname,
+ search,
+ });
describe('ui applications', function describeIndexTests() {
before(async () => {
diff --git a/test/plugin_functional/test_suites/core_plugins/index.js b/test/plugin_functional/test_suites/core_plugins/index.ts
similarity index 81%
rename from test/plugin_functional/test_suites/core_plugins/index.js
rename to test/plugin_functional/test_suites/core_plugins/index.ts
index 376c6f1ebadb1..bf33f37694c3a 100644
--- a/test/plugin_functional/test_suites/core_plugins/index.js
+++ b/test/plugin_functional/test_suites/core_plugins/index.ts
@@ -16,13 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { PluginFunctionalProviderContext } from '../../services';
-export default function ({ loadTestFile }) {
+// eslint-disable-next-line import/no-default-export
+export default function({ loadTestFile }: PluginFunctionalProviderContext) {
describe('core plugins', () => {
loadTestFile(require.resolve('./applications'));
loadTestFile(require.resolve('./legacy_plugins'));
loadTestFile(require.resolve('./server_plugins'));
loadTestFile(require.resolve('./ui_plugins'));
+ loadTestFile(require.resolve('./ui_settings'));
loadTestFile(require.resolve('./top_nav'));
});
}
diff --git a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.js b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts
similarity index 84%
rename from test/plugin_functional/test_suites/core_plugins/legacy_plugins.js
rename to test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts
index c6edf803c9938..d0c01f1e9caf3 100644
--- a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.js
+++ b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts
@@ -18,13 +18,15 @@
*/
import expect from '@kbn/expect';
+import { PluginFunctionalProviderContext } from '../../services';
-export default function ({ getService, getPageObjects }) {
+// eslint-disable-next-line import/no-default-export
+export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
const PageObjects = getPageObjects(['common']);
const testSubjects = getService('testSubjects');
const supertest = getService('supertest');
- describe('legacy plugins', function describeIndexTests() {
+ describe('legacy plugins', () => {
describe('http', () => {
it('has access to New Platform HTTP service', async () => {
await supertest
@@ -41,7 +43,7 @@ export default function ({ getService, getPageObjects }) {
});
});
- describe('application service compatibility layer', function describeIndexTests() {
+ describe('application service compatibility layer', () => {
it('can render legacy apps', async () => {
await PageObjects.common.navigateToApp('core_plugin_legacy');
expect(await testSubjects.exists('coreLegacyCompatH1')).to.be(true);
diff --git a/test/plugin_functional/test_suites/core_plugins/server_plugins.js b/test/plugin_functional/test_suites/core_plugins/server_plugins.ts
similarity index 67%
rename from test/plugin_functional/test_suites/core_plugins/server_plugins.js
rename to test/plugin_functional/test_suites/core_plugins/server_plugins.ts
index a17b19468d6a8..3881af5642996 100644
--- a/test/plugin_functional/test_suites/core_plugins/server_plugins.js
+++ b/test/plugin_functional/test_suites/core_plugins/server_plugins.ts
@@ -16,20 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { PluginFunctionalProviderContext } from '../../services';
-import expect from '@kbn/expect';
-
-export default function ({ getService, getPageObjects }) {
- const PageObjects = getPageObjects(['common']);
- const browser = getService('browser');
+// eslint-disable-next-line import/no-default-export
+export default function({ getService }: PluginFunctionalProviderContext) {
+ const supertest = getService('supertest');
describe('server plugins', function describeIndexTests() {
it('extend request handler context', async () => {
- const url = `${PageObjects.common.getHostPort()}/core_plugin_b/`;
- await browser.get(url);
-
- const pageSource = await browser.execute('return window.document.body.textContent;');
- expect(pageSource).to.equal('Pong via plugin A: true');
+ await supertest
+ .get('/core_plugin_b')
+ .expect(200)
+ .expect('Pong via plugin A: true');
});
});
}
diff --git a/test/plugin_functional/test_suites/core_plugins/ui_plugins.js b/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts
similarity index 84%
rename from test/plugin_functional/test_suites/core_plugins/ui_plugins.js
rename to test/plugin_functional/test_suites/core_plugins/ui_plugins.ts
index 15a4dcabddbd1..a971921ad3ed8 100644
--- a/test/plugin_functional/test_suites/core_plugins/ui_plugins.js
+++ b/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts
@@ -18,12 +18,14 @@
*/
import expect from '@kbn/expect';
+import { PluginFunctionalProviderContext } from '../../services';
-export default function ({ getService, getPageObjects }) {
+// eslint-disable-next-line import/no-default-export
+export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
const PageObjects = getPageObjects(['common']);
const browser = getService('browser');
- describe('ui plugins', function () {
+ describe('ui plugins', function() {
describe('loading', function describeIndexTests() {
before(async () => {
await PageObjects.common.navigateToApp('settings');
@@ -40,7 +42,9 @@ export default function ({ getService, getPageObjects }) {
});
it('should attach string to window.corePluginB', async () => {
- const hasAccessToInjectedMetadata = await browser.execute('return window.hasAccessToInjectedMetadata');
+ const hasAccessToInjectedMetadata = await browser.execute(
+ 'return window.hasAccessToInjectedMetadata'
+ );
expect(hasAccessToInjectedMetadata).to.equal(true);
});
});
@@ -50,7 +54,7 @@ export default function ({ getService, getPageObjects }) {
});
it('should attach pluginContext to window.corePluginB', async () => {
- const envData = await browser.execute('return window.env');
+ const envData: any = await browser.execute('return window.env');
expect(envData.mode.dev).to.be(true);
expect(envData.packageInfo.version).to.be.a('string');
});
diff --git a/test/plugin_functional/test_suites/core_plugins/ui_settings.ts b/test/plugin_functional/test_suites/core_plugins/ui_settings.ts
new file mode 100644
index 0000000000000..2b4227ee798e3
--- /dev/null
+++ b/test/plugin_functional/test_suites/core_plugins/ui_settings.ts
@@ -0,0 +1,52 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import expect from '@kbn/expect';
+import { PluginFunctionalProviderContext } from '../../services';
+
+// eslint-disable-next-line import/no-default-export
+export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
+ const PageObjects = getPageObjects(['common']);
+ const browser = getService('browser');
+ const supertest = getService('supertest');
+
+ describe('ui settings', function() {
+ before(async () => {
+ await PageObjects.common.navigateToApp('settings');
+ });
+
+ it('client plugins have access to registered settings', async () => {
+ const settings = await browser.execute('return window.uiSettingsPlugin');
+ expect(settings).to.eql({
+ category: ['any'],
+ description: 'just for testing',
+ name: 'from_ui_settings_plugin',
+ value: '2',
+ });
+ const settingsValue = await browser.execute('return window.uiSettingsPluginValue');
+ expect(settingsValue).to.be('2');
+ });
+
+ it('server plugins have access to registered settings', async () => {
+ await supertest
+ .get('/api/ui-settings-plugin')
+ .expect(200)
+ .expect({ uiSettingsValue: 2 });
+ });
+ });
+}
diff --git a/yarn.lock b/yarn.lock
index 0c37018bdd596..d28bce24e1922 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3075,6 +3075,11 @@
resolved "https://registry.yarnpkg.com/@types/base64-js/-/base64-js-1.2.5.tgz#582b2476169a6cba460a214d476c744441d873d5"
integrity sha1-WCskdhaabLpGCiFNR2x0REHYc9U=
+"@types/bluebird@*":
+ version "3.5.28"
+ resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.28.tgz#04c1a520ff076649236bc8ca21198542ce2bdb09"
+ integrity sha512-0Vk/kqkukxPKSzP9c8WJgisgGDx5oZDbsLLWIP5t70yThO/YleE+GEm2S1GlRALTaack3O7U5OS5qEm7q2kciA==
+
"@types/bluebird@^3.1.1":
version "3.5.20"
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.20.tgz#f6363172add6f4eabb8cada53ca9af2781e8d6a1"
@@ -4016,6 +4021,22 @@
"@types/cookiejar" "*"
"@types/node" "*"
+"@types/supertest-as-promised@^2.0.38":
+ version "2.0.38"
+ resolved "https://registry.yarnpkg.com/@types/supertest-as-promised/-/supertest-as-promised-2.0.38.tgz#5077adf2a31429e06ba8de6799ebdb796ad50fc7"
+ integrity sha512-2vdlnsZBIgaX0DFNOACK4xFDqvoA1sAR78QD3LiDWGmzSfrRCNt1WFyUYe2Vf0QS03tZf6XC8bNlLaLYXhZbGA==
+ dependencies:
+ "@types/bluebird" "*"
+ "@types/superagent" "*"
+ "@types/supertest" "*"
+
+"@types/supertest@*":
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.8.tgz#23801236e2b85204ed771a8e7c40febba7da2bda"
+ integrity sha512-wcax7/ip4XSSJRLbNzEIUVy2xjcBIZZAuSd2vtltQfRK7kxhx5WMHbLHkYdxN3wuQCrwpYrg86/9byDjPXoGMA==
+ dependencies:
+ "@types/superagent" "*"
+
"@types/supertest@^2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.5.tgz#18d082a667eaed22759be98f4923e0061ae70c62"