): void;
-}
-
// @public
export interface IRouter {
delete: (route: RouteConfig
, handler: RequestHandler
) => void;
@@ -763,11 +735,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;
@@ -840,7 +809,7 @@ export interface LegacyRequest extends Request {
// @public @deprecated (undocumented)
export interface LegacyServiceSetupDeps {
- // Warning: (ae-incompatible-release-tags) The symbol "core" is marked as @public, but its signature references "InternalCoreSetup" which is marked as @internal
+ // Warning: (ae-forgotten-export) The symbol "InternalCoreSetup" needs to be exported by the entry point index.d.ts
//
// (undocumented)
core: InternalCoreSetup & {
@@ -852,7 +821,7 @@ export interface LegacyServiceSetupDeps {
// @public @deprecated (undocumented)
export interface LegacyServiceStartDeps {
- // Warning: (ae-incompatible-release-tags) The symbol "core" is marked as @public, but its signature references "InternalCoreStart" which is marked as @internal
+ // Warning: (ae-forgotten-export) The symbol "InternalCoreStart" needs to be exported by the entry point index.d.ts
//
// (undocumented)
core: InternalCoreStart & {
@@ -942,6 +911,9 @@ export type MIGRATION_ASSISTANCE_INDEX_ACTION = 'upgrade' | 'reindex';
// @public (undocumented)
export type MIGRATION_DEPRECATION_LEVEL = 'none' | 'info' | 'warning' | 'critical';
+// @public
+export type MutatingOperationRefreshSetting = boolean | 'wait_for';
+
// Warning: (ae-forgotten-export) The symbol "OnPostAuthResult" needs to be exported by the entry point index.d.ts
//
// @public
@@ -1071,6 +1043,9 @@ export interface RequestHandlerContext {
dataClient: IScopedClusterClient;
adminClient: IScopedClusterClient;
};
+ uiSettings: {
+ client: IUiSettingsClient;
+ };
};
}
@@ -1196,6 +1171,11 @@ export interface SavedObjectsBulkUpdateObject {
// (undocumented)
@@ -1208,9 +1188,9 @@ export class SavedObjectsClient {
constructor(repository: SavedObjectsRepository);
bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>;
bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>;
- bulkUpdate(objects: Array>, options?: SavedObjectsBaseOptions): Promise>;
+ bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>;
create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>;
- delete(type: string, id: string, options?: SavedObjectsBaseOptions): Promise<{}>;
+ delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>;
// (undocumented)
errors: typeof SavedObjectsErrorHelpers;
// (undocumented)
@@ -1247,6 +1227,12 @@ export interface SavedObjectsCreateOptions extends SavedObjectsBaseOptions {
overwrite?: boolean;
// (undocumented)
references?: SavedObjectReference[];
+ refresh?: MutatingOperationRefreshSetting;
+}
+
+// @public (undocumented)
+export interface SavedObjectsDeleteOptions extends SavedObjectsBaseOptions {
+ refresh?: MutatingOperationRefreshSetting;
}
// @public (undocumented)
@@ -1476,6 +1462,8 @@ export interface SavedObjectsLegacyService {
// (undocumented)
schema: SavedObjectsSchema;
// (undocumented)
+ setScopedSavedObjectsClientFactory: SavedObjectsClientProvider['setClientFactory'];
+ // (undocumented)
types: string[];
}
@@ -1554,6 +1542,7 @@ export class SavedObjectsSerializer {
// @public (undocumented)
export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions {
references?: SavedObjectReference[];
+ refresh?: MutatingOperationRefreshSetting;
version?: string;
}
@@ -1595,24 +1584,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.test.ts b/src/core/server/server.test.ts
index aee6461580654..f912a31901ad8 100644
--- a/src/core/server/server.test.ts
+++ b/src/core/server/server.test.ts
@@ -70,7 +70,10 @@ test('injects legacy dependency to context#setup()', async () => {
const pluginA = Symbol();
const pluginB = Symbol();
- const pluginDependencies = new Map([[pluginA, []], [pluginB, [pluginA]]]);
+ const pluginDependencies = new Map([
+ [pluginA, []],
+ [pluginB, [pluginA]],
+ ]);
mockPluginsService.discover.mockResolvedValue(pluginDependencies);
await server.setup();
diff --git a/src/core/server/server.ts b/src/core/server/server.ts
index 49136c8e09768..6c38de03f0f2d 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';
@@ -40,6 +40,7 @@ import { mapToObject } from '../utils/';
import { ContextService } from './context';
import { SavedObjectsServiceSetup } from './saved_objects/saved_objects_service';
import { RequestHandlerContext } from '.';
+import { InternalCoreSetup } from './internal_types';
const coreId = Symbol('core');
@@ -102,7 +103,7 @@ export class Server {
http: httpSetup,
});
- const coreSetup = {
+ const coreSetup: InternalCoreSetup = {
context: contextServiceSetup,
elasticsearch: elasticsearchServiceSetup,
http: httpSetup,
@@ -121,7 +122,7 @@ export class Server {
legacy: legacySetup,
});
- this.registerCoreContext({ ...coreSetup, savedObjects: savedObjectsSetup });
+ this.registerCoreContext(coreSetup, savedObjectsSetup);
return coreSetup;
}
@@ -163,27 +164,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: