From e0a519424fce5758434b914c38d877cbc7588f93 Mon Sep 17 00:00:00 2001
From: Matthew Kime <matt@mattki.me>
Date: Wed, 8 Apr 2020 15:10:44 -0500
Subject: [PATCH 01/78] Index pattern management plugin -
 src/legacy/core_plugins/management => new platform plugin (#62594)

* implement index pattern management plugin in new platform
---
 .i18nrc.json                                  |  1 +
 .../services => kibana/public}/index.ts       |  5 +-
 .../step_index_pattern.test.tsx               |  2 +-
 .../step_index_pattern/step_index_pattern.tsx |  2 +-
 .../step_time_field/step_time_field.test.tsx  |  2 +-
 .../step_time_field/step_time_field.tsx       |  2 +-
 .../create_index_pattern_wizard/index.js      |  3 +-
 .../lib/get_indices.test.ts                   |  2 +-
 .../lib/get_indices.ts                        |  2 +-
 .../edit_index_pattern/edit_index_pattern.js  | 13 ++---
 .../sections/index_patterns/index.js          |  5 +-
 .../__jest__/objects_table.test.js            |  4 +-
 .../components/flyout/__jest__/flyout.test.js |  4 +-
 src/legacy/core_plugins/management/index.ts   | 37 -------------
 .../core_plugins/management/package.json      |  5 --
 .../core_plugins/management/public/index.ts   | 38 --------------
 .../core_plugins/management/public/legacy.ts  | 45 ----------------
 .../new_platform/new_platform.karma_mock.js   | 15 ++++++
 .../ui/public/new_platform/new_platform.ts    |  6 +++
 .../index_pattern_management/kibana.json      |  7 +++
 .../index_pattern_management/public}/index.ts | 11 ++--
 .../index_pattern_management/public}/mocks.ts | 52 +++++++++----------
 .../public}/plugin.ts                         | 41 +++++++--------
 .../public/service}/creation/config.ts        |  8 +--
 .../public/service}/creation/index.ts         |  0
 .../public/service}/creation/manager.ts       | 21 ++++++--
 .../public/service}/index.ts                  |  0
 .../index_pattern_management_service.ts       | 51 ++++++++----------
 .../public/service}/list/config.ts            |  9 ++--
 .../public/service}/list/index.ts             |  0
 .../public/service}/list/manager.ts           | 18 +++++--
 x-pack/legacy/plugins/rollup/kibana.json      |  3 +-
 .../rollup_index_pattern_creation_config.js   |  2 +-
 .../rollup_index_pattern_list_config.js       |  2 +-
 x-pack/legacy/plugins/rollup/public/legacy.ts |  8 +--
 x-pack/legacy/plugins/rollup/public/plugin.ts | 17 ++----
 .../components/copy_to_space_flyout.test.tsx  |  6 ---
 .../components/copy_to_space_flyout.tsx       |  2 +-
 .../copy_to_space_flyout_footer.tsx           |  2 +-
 .../components/processing_copy_to_space.tsx   |  2 +-
 .../summarize_copy_result.test.ts             |  2 +-
 .../summarize_copy_result.ts                  |  2 +-
 .../translations/translations/ja-JP.json      | 10 ++--
 .../translations/translations/zh-CN.json      | 10 ++--
 44 files changed, 183 insertions(+), 296 deletions(-)
 rename src/legacy/core_plugins/{management/public/np_ready/services => kibana/public}/index.ts (86%)
 delete mode 100644 src/legacy/core_plugins/management/index.ts
 delete mode 100644 src/legacy/core_plugins/management/package.json
 delete mode 100644 src/legacy/core_plugins/management/public/index.ts
 delete mode 100644 src/legacy/core_plugins/management/public/legacy.ts
 create mode 100644 src/plugins/index_pattern_management/kibana.json
 rename src/{legacy/core_plugins/management/public/np_ready => plugins/index_pattern_management/public}/index.ts (83%)
 rename src/{legacy/core_plugins/management/public/np_ready => plugins/index_pattern_management/public}/mocks.ts (57%)
 rename src/{legacy/core_plugins/management/public/np_ready => plugins/index_pattern_management/public}/plugin.ts (60%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/creation/config.ts (88%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/creation/index.ts (100%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/creation/manager.ts (79%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/index.ts (100%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/index_pattern_management_service.ts (51%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/list/config.ts (87%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/list/index.ts (100%)
 rename src/{legacy/core_plugins/management/public/np_ready/services/index_pattern_management => plugins/index_pattern_management/public/service}/list/manager.ts (75%)

diff --git a/.i18nrc.json b/.i18nrc.json
index 3b0b40b40792e..19d361aed9344 100644
--- a/.i18nrc.json
+++ b/.i18nrc.json
@@ -24,6 +24,7 @@
       "src/legacy/core_plugins/management",
       "src/plugins/management"
     ],
+    "indexPatternManagement": "src/plugins/index_pattern_management",
     "advancedSettings": "src/plugins/advanced_settings",
     "kibana_legacy": "src/plugins/kibana_legacy",
     "kibana_react": "src/legacy/core_plugins/kibana_react",
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index.ts b/src/legacy/core_plugins/kibana/public/index.ts
similarity index 86%
rename from src/legacy/core_plugins/management/public/np_ready/services/index.ts
rename to src/legacy/core_plugins/kibana/public/index.ts
index 9df010223542b..a4fffc6eec26d 100644
--- a/src/legacy/core_plugins/management/public/np_ready/services/index.ts
+++ b/src/legacy/core_plugins/kibana/public/index.ts
@@ -17,4 +17,7 @@
  * under the License.
  */
 
-export * from './index_pattern_management';
+export {
+  ProcessedImportResponse,
+  processImportResponse,
+} from './management/sections/objects/lib/process_import_response';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.test.tsx
index 25bd36829b6d0..40471b95d774c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.test.tsx
@@ -21,7 +21,7 @@ import React from 'react';
 import { StepIndexPattern } from '../step_index_pattern';
 import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
 import { Header } from './components/header';
-import { IndexPatternCreationConfig } from '../../../../../../../../management/public';
+import { IndexPatternCreationConfig } from '../../../../../../../../../../plugins/index_pattern_management/public';
 import { coreMock } from '../../../../../../../../../../core/public/mocks';
 import { dataPluginMock } from '../../../../../../../../../../plugins/data/public/mocks';
 import { SavedObjectsFindResponsePublic } from '../../../../../../../../../../core/public';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx
index bbb6bf26e5b31..648bf7f8f9738 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx
@@ -39,7 +39,7 @@ import { LoadingIndices } from './components/loading_indices';
 import { StatusMessage } from './components/status_message';
 import { IndicesList } from './components/indices_list';
 import { Header } from './components/header';
-import { IndexPatternCreationConfig } from '../../../../../../../../management/public';
+import { IndexPatternCreationConfig } from '../../../../../../../../../../plugins/index_pattern_management/public';
 import { MatchedIndex } from '../../types';
 
 interface StepIndexPatternProps {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx
index e0c43105cb320..b23b1e3ad9051 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx
@@ -19,7 +19,7 @@
 
 import React from 'react';
 import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
-import { IndexPatternCreationConfig } from '../../../../../../../../management/public';
+import { IndexPatternCreationConfig } from '../../../../../../../../../../plugins/index_pattern_management/public';
 import { IFieldType } from '../../../../../../../../../../plugins/data/public';
 
 import { StepTimeField } from '../step_time_field';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx
index 80582cc1fbd92..a58bf10c9dab8 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx
@@ -34,7 +34,7 @@ import { Header } from './components/header';
 import { TimeField } from './components/time_field';
 import { AdvancedOptions } from './components/advanced_options';
 import { ActionButtons } from './components/action_buttons';
-import { IndexPatternCreationConfig } from '../../../../../../../../management/public';
+import { IndexPatternCreationConfig } from '../../../../../../../../../../plugins/index_pattern_management/public';
 import { DataPublicPluginStart } from '../../../../../../../../../../plugins/data/public';
 
 interface StepTimeFieldProps {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js
index 50c5a58d35db3..47cb773258cb4 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js
@@ -20,7 +20,6 @@
 import uiRoutes from 'ui/routes';
 import angularTemplate from './angular_template.html';
 import { npStart } from 'ui/new_platform';
-import { setup as managementSetup } from '../../../../../../management/public/legacy';
 import { getCreateBreadcrumbs } from '../breadcrumbs';
 
 import { renderCreateIndexPatternWizard, destroyCreateIndexPatternWizard } from './render';
@@ -33,7 +32,7 @@ uiRoutes.when('/management/kibana/index_pattern', {
     const kbnUrl = $injector.get('kbnUrl');
     $scope.$$postDigest(() => {
       const $routeParams = $injector.get('$routeParams');
-      const indexPatternCreationType = managementSetup.indexPattern.creation.getType(
+      const indexPatternCreationType = npStart.plugins.indexPatternManagement.creation.getType(
         $routeParams.type
       );
       const services = {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts
index 5a8460fcb51ba..40583af7177fe 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts
@@ -18,7 +18,7 @@
  */
 
 import { getIndices } from './get_indices';
-import { IndexPatternCreationConfig } from './../../../../../../../management/public';
+import { IndexPatternCreationConfig } from '../../../../../../../../../plugins/index_pattern_management/public';
 // eslint-disable-next-line @kbn/eslint/no-restricted-paths
 import { LegacyApiCaller } from '../../../../../../../../../plugins/data/public/search';
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts
index 3848c425e2d49..3b1b7a3b52a5b 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts
@@ -18,7 +18,7 @@
  */
 
 import { get, sortBy } from 'lodash';
-import { IndexPatternCreationConfig } from '../../../../../../../management/public';
+import { IndexPatternCreationConfig } from '../../../../../../../../../plugins/index_pattern_management/public';
 import { DataPublicPluginStart } from '../../../../../../../../../plugins/data/public';
 import { MatchedIndex } from '../types';
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js
index 6d302ac5a74f3..594430ca01f4c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js
@@ -29,7 +29,6 @@ import { uiModules } from 'ui/modules';
 import template from './edit_index_pattern.html';
 import { fieldWildcardMatcher } from '../../../../../../../../plugins/kibana_utils/public';
 import { subscribeWithScope } from '../../../../../../../../plugins/kibana_legacy/public';
-import { setup as managementSetup } from '../../../../../../management/public/legacy';
 import React from 'react';
 import { render, unmountComponentAtNode } from 'react-dom';
 import { SourceFiltersTable } from './source_filters_table';
@@ -239,14 +238,12 @@ uiModules
     $scope.editSectionsProvider = Private(IndicesEditSectionsProvider);
     $scope.kbnUrl = Private(KbnUrlProvider);
     $scope.indexPattern = $route.current.locals.indexPattern;
-    $scope.indexPatternListProvider = managementSetup.indexPattern.list;
-    $scope.indexPattern.tags = managementSetup.indexPattern.list.getIndexPatternTags(
+    $scope.indexPatternListProvider = npStart.plugins.indexPatternManagement.list;
+    $scope.indexPattern.tags = npStart.plugins.indexPatternManagement.list.getIndexPatternTags(
       $scope.indexPattern,
       $scope.indexPattern.id === config.get('defaultIndex')
     );
-    $scope.getFieldInfo = managementSetup.indexPattern.list.getFieldInfo.bind(
-      managementSetup.indexPattern.list
-    );
+    $scope.getFieldInfo = npStart.plugins.indexPatternManagement.list.getFieldInfo;
     docTitle.change($scope.indexPattern.title);
 
     const otherPatterns = _.filter($route.current.locals.indexPatterns, pattern => {
@@ -257,7 +254,7 @@ uiModules
       $scope.editSections = $scope.editSectionsProvider(
         $scope.indexPattern,
         $scope.fieldFilter,
-        managementSetup.indexPattern.list
+        npStart.plugins.indexPatternManagement.list
       );
       $scope.refreshFilters();
       $scope.fields = $scope.indexPattern.getNonScriptedFields();
@@ -363,7 +360,7 @@ uiModules
       $scope.editSections = $scope.editSectionsProvider(
         $scope.indexPattern,
         $scope.fieldFilter,
-        managementSetup.indexPattern.list
+        npStart.plugins.indexPatternManagement.list
       );
 
       if ($scope.fieldFilter === undefined) {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js
index 310797a7f3a0c..a8376c0e84bf9 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/index.js
@@ -18,7 +18,6 @@
  */
 
 import { management } from 'ui/management';
-import { setup as managementSetup } from '../../../../../management/public/legacy';
 import './create_index_pattern_wizard';
 import './edit_index_pattern';
 import uiRoutes from 'ui/routes';
@@ -111,7 +110,7 @@ uiModules
       transclude: true,
       template: indexTemplate,
       link: async function($scope) {
-        const indexPatternCreationOptions = await managementSetup.indexPattern.creation.getIndexPatternCreationOptions(
+        const indexPatternCreationOptions = await npStart.plugins.indexPatternManagement.creation.getIndexPatternCreationOptions(
           url => {
             $scope.$evalAsync(() => kbnUrl.change(url));
           }
@@ -124,7 +123,7 @@ uiModules
                 const id = pattern.id;
                 const title = pattern.get('title');
                 const isDefault = $scope.defaultIndex === id;
-                const tags = managementSetup.indexPattern.list.getIndexPatternTags(
+                const tags = npStart.plugins.indexPatternManagement.list.getIndexPatternTags(
                   pattern,
                   isDefault
                 );
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
index a5e34f8955fe3..7b9c17640a0f3 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
@@ -19,7 +19,7 @@
 
 import React from 'react';
 import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
-import { mockManagementPlugin } from '../../../../../../../../management/public/np_ready/mocks';
+import { mockManagementPlugin } from '../../../../../../../../../../plugins/index_pattern_management/public/mocks';
 import { Query } from '@elastic/eui';
 
 import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table';
@@ -30,7 +30,7 @@ import { extractExportDetails } from '../../../lib/extract_export_details';
 
 jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
 
-jest.mock('../../../../../../../../management/public/legacy', () => ({
+jest.mock('../../../../../../../../../../plugins/index_pattern_management/public', () => ({
   setup: mockManagementPlugin.createSetupContract(),
   start: mockManagementPlugin.createStartContract(),
 }));
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
index 97c0d5b89d657..5d14c4609b918 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
@@ -19,7 +19,7 @@
 
 import React from 'react';
 import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
-import { mockManagementPlugin } from '../../../../../../../../../../management/public/np_ready/mocks';
+import { mockManagementPlugin } from '../../../../../../../../../../../../plugins/index_pattern_management/public/mocks';
 import { Flyout } from '../flyout';
 
 jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
@@ -48,7 +48,7 @@ jest.mock('../../../../../lib/resolve_saved_objects', () => ({
   saveObjects: jest.fn(),
 }));
 
-jest.mock('../../../../../../../../../../management/public/legacy', () => ({
+jest.mock('../../../../../../../../../../../../plugins/index_pattern_management/public', () => ({
   setup: mockManagementPlugin.createSetupContract(),
   start: mockManagementPlugin.createStartContract(),
 }));
diff --git a/src/legacy/core_plugins/management/index.ts b/src/legacy/core_plugins/management/index.ts
deleted file mode 100644
index 4962c948f842f..0000000000000
--- a/src/legacy/core_plugins/management/index.ts
+++ /dev/null
@@ -1,37 +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 { resolve } from 'path';
-import { Legacy } from '../../../../kibana';
-
-// eslint-disable-next-line import/no-default-export
-export default function ManagementPlugin(kibana: any) {
-  const config: Legacy.PluginSpecOptions = {
-    id: 'stack-management',
-    publicDir: resolve(__dirname, 'public'),
-    config: (Joi: any) => {
-      return Joi.object({
-        enabled: Joi.boolean().default(true),
-      }).default();
-    },
-    init: (server: Legacy.Server) => ({}),
-  };
-
-  return new kibana.Plugin(config);
-}
diff --git a/src/legacy/core_plugins/management/package.json b/src/legacy/core_plugins/management/package.json
deleted file mode 100644
index 77d33a7bce3b6..0000000000000
--- a/src/legacy/core_plugins/management/package.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "management",
-  "version": "kibana"
-}
-  
\ No newline at end of file
diff --git a/src/legacy/core_plugins/management/public/index.ts b/src/legacy/core_plugins/management/public/index.ts
deleted file mode 100644
index bc3737524e125..0000000000000
--- a/src/legacy/core_plugins/management/public/index.ts
+++ /dev/null
@@ -1,38 +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.
- */
-
-/**
- * Static np-ready code, re-exported here so consumers can import from
- * `src/legacy/core_plugins/management/public`
- *
- * @public
- */
-
-export {
-  ManagementSetup,
-  ManagementStart,
-  plugin,
-  IndexPatternCreationConfig,
-  IndexPatternListConfig,
-} from './np_ready';
-
-export {
-  processImportResponse,
-  ProcessedImportResponse,
-} from '../../kibana/public/management/sections/objects/lib/process_import_response';
diff --git a/src/legacy/core_plugins/management/public/legacy.ts b/src/legacy/core_plugins/management/public/legacy.ts
deleted file mode 100644
index 96d2c74398a0e..0000000000000
--- a/src/legacy/core_plugins/management/public/legacy.ts
+++ /dev/null
@@ -1,45 +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.
- */
-
-/**
- * New Platform Shim
- *
- * In this file, we import any legacy dependencies we have, and shim them into
- * our plugin by manually constructing the values that the new platform will
- * eventually be passing to the `setup/start` method of our plugin definition.
- *
- * The idea is that our `plugin.ts` can stay "pure" and not contain any legacy
- * world code. Then when it comes time to migrate to the new platform, we can
- * simply delete this shim file.
- *
- * We are also calling `setup/start` here and exporting our public contract so that
- * other legacy plugins are able to import from '../core_plugins/management/legacy'
- * and receive the response value of the `setup/start` contract, mimicking the
- * data that will eventually be injected by the new platform.
- */
-
-import { PluginInitializerContext } from 'src/core/public';
-import { npSetup, npStart } from 'ui/new_platform';
-
-import { plugin } from '.';
-
-const pluginInstance = plugin({} as PluginInitializerContext);
-
-export const setup = pluginInstance.setup(npSetup.core, { home: npSetup.plugins.home });
-export const start = pluginInstance.start(npStart.core, {});
diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
index f70ef069dd134..0779d6472671c 100644
--- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
+++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
@@ -290,6 +290,10 @@ export const npSetup = {
         }),
       },
     },
+    indexPatternManagement: {
+      list: { addListConfig: sinon.fake() },
+      creation: { addCreationConfig: sinon.fake() },
+    },
     discover: {
       docViews: {
         addDocView: sinon.fake(),
@@ -325,6 +329,17 @@ export const npStart = {
         }),
       },
     },
+    indexPatternManagement: {
+      list: {
+        getType: sinon.fake(),
+        getIndexPatternCreationOptions: sinon.fake(),
+      },
+      creation: {
+        getIndexPatternTags: sinon.fake(),
+        getFieldInfo: sinon.fake(),
+        areScriptedFieldsEnabled: sinon.fake(),
+      },
+    },
     embeddable: {
       getEmbeddableFactory: sinon.fake(),
       getEmbeddableFactories: sinon.fake(),
diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts
index b4b5099081759..cdd7e1a994912 100644
--- a/src/legacy/ui/public/new_platform/new_platform.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.ts
@@ -47,6 +47,10 @@ import {
   AdvancedSettingsStart,
 } from '../../../../plugins/advanced_settings/public';
 import { ManagementSetup, ManagementStart } from '../../../../plugins/management/public';
+import {
+  IndexPatternManagementSetup,
+  IndexPatternManagementStart,
+} from '../../../../plugins/index_pattern_management/public';
 import { BfetchPublicSetup, BfetchPublicStart } from '../../../../plugins/bfetch/public';
 import { UsageCollectionSetup } from '../../../../plugins/usage_collection/public';
 import { TelemetryPluginSetup, TelemetryPluginStart } from '../../../../plugins/telemetry/public';
@@ -86,6 +90,7 @@ export interface PluginsSetup {
   visualizations: VisualizationsSetup;
   telemetry?: TelemetryPluginSetup;
   savedObjectsManagement: SavedObjectsManagementPluginSetup;
+  indexPatternManagement: IndexPatternManagementSetup;
 }
 
 export interface PluginsStart {
@@ -107,6 +112,7 @@ export interface PluginsStart {
   telemetry?: TelemetryPluginStart;
   dashboard: DashboardStart;
   savedObjectsManagement: SavedObjectsManagementPluginStart;
+  indexPatternManagement: IndexPatternManagementStart;
 }
 
 export const npSetup = {
diff --git a/src/plugins/index_pattern_management/kibana.json b/src/plugins/index_pattern_management/kibana.json
new file mode 100644
index 0000000000000..d5397a11184aa
--- /dev/null
+++ b/src/plugins/index_pattern_management/kibana.json
@@ -0,0 +1,7 @@
+{
+  "id": "indexPatternManagement",
+  "version": "kibana",
+  "server": false,
+  "ui": true,
+  "requiredPlugins": []
+}
diff --git a/src/legacy/core_plugins/management/public/np_ready/index.ts b/src/plugins/index_pattern_management/public/index.ts
similarity index 83%
rename from src/legacy/core_plugins/management/public/np_ready/index.ts
rename to src/plugins/index_pattern_management/public/index.ts
index bae0f1d3e23cd..da482c0c51f0a 100644
--- a/src/legacy/core_plugins/management/public/np_ready/index.ts
+++ b/src/plugins/index_pattern_management/public/index.ts
@@ -29,14 +29,11 @@
  * either types, or static code.
  */
 import { PluginInitializerContext } from 'src/core/public';
-import { ManagementPlugin } from './plugin';
-export { ManagementSetup, ManagementStart } from './plugin';
+import { IndexPatternManagementPlugin } from './plugin';
+export { IndexPatternManagementSetup, IndexPatternManagementStart } from './plugin';
 
 export function plugin(initializerContext: PluginInitializerContext) {
-  return new ManagementPlugin(initializerContext);
+  return new IndexPatternManagementPlugin(initializerContext);
 }
 
-export {
-  IndexPatternCreationConfig,
-  IndexPatternListConfig,
-} from './services/index_pattern_management';
+export { IndexPatternCreationConfig, IndexPatternListConfig } from './service';
diff --git a/src/legacy/core_plugins/management/public/np_ready/mocks.ts b/src/plugins/index_pattern_management/public/mocks.ts
similarity index 57%
rename from src/legacy/core_plugins/management/public/np_ready/mocks.ts
rename to src/plugins/index_pattern_management/public/mocks.ts
index ae0be98de63f3..bc97f46c302e3 100644
--- a/src/legacy/core_plugins/management/public/np_ready/mocks.ts
+++ b/src/plugins/index_pattern_management/public/mocks.ts
@@ -18,42 +18,38 @@
  */
 
 import { PluginInitializerContext } from 'src/core/public';
-import { coreMock } from '../../../../../core/public/mocks';
+import { coreMock } from '../../../core/public/mocks';
 import {
-  ManagementSetup,
-  ManagementStart,
-  ManagementPlugin,
-  ManagementPluginSetupDependencies,
+  IndexPatternManagementSetup,
+  IndexPatternManagementStart,
+  IndexPatternManagementPlugin,
 } from './plugin';
 
-const createSetupContract = (): ManagementSetup => ({
-  indexPattern: {
-    creation: {
-      add: jest.fn(),
-      getType: jest.fn(),
-      getIndexPatternCreationOptions: jest.fn(),
-    } as any,
-    list: {
-      add: jest.fn(),
-      getIndexPatternTags: jest.fn(),
-      getFieldInfo: jest.fn(),
-      areScriptedFieldsEnabled: jest.fn(),
-    } as any,
-  },
+const createSetupContract = (): IndexPatternManagementSetup => ({
+  creation: {
+    addCreationConfig: jest.fn(),
+  } as any,
+  list: {
+    addListConfig: jest.fn(),
+  } as any,
 });
 
-const createStartContract = (): ManagementStart => ({});
+const createStartContract = (): IndexPatternManagementStart => ({
+  creation: {
+    getType: jest.fn(),
+    getIndexPatternCreationOptions: jest.fn(),
+  } as any,
+  list: {
+    getIndexPatternTags: jest.fn(),
+    getFieldInfo: jest.fn(),
+    areScriptedFieldsEnabled: jest.fn(),
+  } as any,
+});
 
 const createInstance = async () => {
-  const plugin = new ManagementPlugin({} as PluginInitializerContext);
+  const plugin = new IndexPatternManagementPlugin({} as PluginInitializerContext);
 
-  const setup = plugin.setup(coreMock.createSetup(), ({
-    home: {
-      featureCatalogue: {
-        register: jest.fn(),
-      },
-    },
-  } as unknown) as ManagementPluginSetupDependencies);
+  const setup = plugin.setup(coreMock.createSetup());
   const doStart = () => plugin.start(coreMock.createStart(), {});
 
   return {
diff --git a/src/legacy/core_plugins/management/public/np_ready/plugin.ts b/src/plugins/index_pattern_management/public/plugin.ts
similarity index 60%
rename from src/legacy/core_plugins/management/public/np_ready/plugin.ts
rename to src/plugins/index_pattern_management/public/plugin.ts
index 2a8ef10c817cc..93bb0ead1df4a 100644
--- a/src/legacy/core_plugins/management/public/np_ready/plugin.ts
+++ b/src/plugins/index_pattern_management/public/plugin.ts
@@ -17,43 +17,40 @@
  * under the License.
  */
 import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
-import { HomePublicPluginSetup } from 'src/plugins/home/public';
-import { IndexPatternManagementService, IndexPatternManagementSetup } from './services';
+import {
+  IndexPatternManagementService,
+  IndexPatternManagementServiceSetup,
+  IndexPatternManagementServiceStart,
+} from './service';
 
-export interface ManagementPluginSetupDependencies {
-  home: HomePublicPluginSetup;
-}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface IndexPatternManagementSetupDependencies {}
 
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface ManagementPluginStartDependencies {}
+export interface IndexPatternManagementStartDependencies {}
 
-export interface ManagementSetup {
-  indexPattern: IndexPatternManagementSetup;
-}
+export type IndexPatternManagementSetup = IndexPatternManagementServiceSetup;
 
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-export interface ManagementStart {}
+export type IndexPatternManagementStart = IndexPatternManagementServiceStart;
 
-export class ManagementPlugin
+export class IndexPatternManagementPlugin
   implements
     Plugin<
-      ManagementSetup,
-      ManagementStart,
-      ManagementPluginSetupDependencies,
-      ManagementPluginStartDependencies
+      IndexPatternManagementSetup,
+      IndexPatternManagementStart,
+      IndexPatternManagementSetupDependencies,
+      IndexPatternManagementStartDependencies
     > {
   private readonly indexPattern = new IndexPatternManagementService();
 
   constructor(initializerContext: PluginInitializerContext) {}
 
-  public setup(core: CoreSetup, { home }: ManagementPluginSetupDependencies) {
-    return {
-      indexPattern: this.indexPattern.setup({ httpClient: core.http, home }),
-    };
+  public setup(core: CoreSetup) {
+    return this.indexPattern.setup({ httpClient: core.http });
   }
 
-  public start(core: CoreStart, plugins: ManagementPluginStartDependencies) {
-    return {};
+  public start(core: CoreStart, plugins: IndexPatternManagementStartDependencies) {
+    return this.indexPattern.start();
   }
 
   public stop() {
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts b/src/plugins/index_pattern_management/public/service/creation/config.ts
similarity index 88%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts
rename to src/plugins/index_pattern_management/public/service/creation/config.ts
index 5714fa3338962..29ab0ebfc3d5f 100644
--- a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts
+++ b/src/plugins/index_pattern_management/public/service/creation/config.ts
@@ -18,20 +18,20 @@
  */
 
 import { i18n } from '@kbn/i18n';
-import { MatchedIndex } from '../../../../../../kibana/public/management/sections/index_patterns/create_index_pattern_wizard/types';
+import { MatchedIndex } from '../../../../../legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/types';
 
 const indexPatternTypeName = i18n.translate(
-  'management.editIndexPattern.createIndex.defaultTypeName',
+  'indexPatternManagement.editIndexPattern.createIndex.defaultTypeName',
   { defaultMessage: 'index pattern' }
 );
 
 const indexPatternButtonText = i18n.translate(
-  'management.editIndexPattern.createIndex.defaultButtonText',
+  'indexPatternManagement.editIndexPattern.createIndex.defaultButtonText',
   { defaultMessage: 'Standard index pattern' }
 );
 
 const indexPatternButtonDescription = i18n.translate(
-  'management.editIndexPattern.createIndex.defaultButtonDescription',
+  'indexPatternManagement.editIndexPattern.createIndex.defaultButtonDescription',
   { defaultMessage: 'Perform full aggregations against any data' }
 );
 
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/index.ts b/src/plugins/index_pattern_management/public/service/creation/index.ts
similarity index 100%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/index.ts
rename to src/plugins/index_pattern_management/public/service/creation/index.ts
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/manager.ts b/src/plugins/index_pattern_management/public/service/creation/manager.ts
similarity index 79%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/manager.ts
rename to src/plugins/index_pattern_management/public/service/creation/manager.ts
index e7fa13409ab04..32b3e7ee7a133 100644
--- a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/manager.ts
+++ b/src/plugins/index_pattern_management/public/service/creation/manager.ts
@@ -17,23 +17,25 @@
  * under the License.
  */
 
-import { HttpSetup } from '../../../../../../../../core/public';
+import { HttpSetup } from '../../../../../core/public';
 import { IndexPatternCreationConfig, UrlHandler, IndexPatternCreationOption } from './config';
 
 export class IndexPatternCreationManager {
   private configs: IndexPatternCreationConfig[];
 
-  constructor(private readonly httpClient: HttpSetup) {
+  constructor() {
     this.configs = [];
   }
 
-  public add(Config: typeof IndexPatternCreationConfig) {
-    const config = new Config({ httpClient: this.httpClient });
+  public addCreationConfig = (httpClient: HttpSetup) => (
+    Config: typeof IndexPatternCreationConfig
+  ) => {
+    const config = new Config({ httpClient });
     if (this.configs.findIndex(c => c.key === config.key) !== -1) {
       throw new Error(`${config.key} exists in IndexPatternCreationManager.`);
     }
     this.configs.push(config);
-  }
+  };
 
   public getType(key: string | undefined): IndexPatternCreationConfig | null {
     if (key) {
@@ -58,4 +60,13 @@ export class IndexPatternCreationManager {
     );
     return options;
   }
+
+  setup = (httpClient: HttpSetup) => ({
+    addCreationConfig: this.addCreationConfig(httpClient).bind(this),
+  });
+
+  start = () => ({
+    getType: this.getType.bind(this),
+    getIndexPatternCreationOptions: this.getIndexPatternCreationOptions.bind(this),
+  });
 }
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index.ts b/src/plugins/index_pattern_management/public/service/index.ts
similarity index 100%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index.ts
rename to src/plugins/index_pattern_management/public/service/index.ts
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index_pattern_management_service.ts b/src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts
similarity index 51%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index_pattern_management_service.ts
rename to src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts
index 2b6f008dd928a..4780fa00ed468 100644
--- a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/index_pattern_management_service.ts
+++ b/src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts
@@ -17,18 +17,12 @@
  * under the License.
  */
 
-import { i18n } from '@kbn/i18n';
-import {
-  FeatureCatalogueCategory,
-  HomePublicPluginSetup,
-} from '../../../../../../../plugins/home/public';
-import { HttpSetup } from '../../../../../../../core/public';
+import { HttpSetup } from '../../../../core/public';
 import { IndexPatternCreationManager, IndexPatternCreationConfig } from './creation';
 import { IndexPatternListManager, IndexPatternListConfig } from './list';
 
 interface SetupDependencies {
   httpClient: HttpSetup;
-  home: HomePublicPluginSetup;
 }
 
 /**
@@ -37,31 +31,29 @@ interface SetupDependencies {
  * @internal
  */
 export class IndexPatternManagementService {
-  public setup({ httpClient, home }: SetupDependencies) {
-    const creation = new IndexPatternCreationManager(httpClient);
-    const list = new IndexPatternListManager();
+  indexPatternCreationManager: IndexPatternCreationManager;
+  indexPatternListConfig: IndexPatternListManager;
 
-    creation.add(IndexPatternCreationConfig);
-    list.add(IndexPatternListConfig);
+  constructor() {
+    this.indexPatternCreationManager = new IndexPatternCreationManager();
+    this.indexPatternListConfig = new IndexPatternListManager();
+  }
+
+  public setup({ httpClient }: SetupDependencies) {
+    const creationManagerSetup = this.indexPatternCreationManager.setup(httpClient);
+    creationManagerSetup.addCreationConfig(IndexPatternCreationConfig);
+    this.indexPatternListConfig.setup().addListConfig(IndexPatternListConfig);
 
-    home.featureCatalogue.register({
-      id: 'index_patterns',
-      title: i18n.translate('management.indexPatternHeader', {
-        defaultMessage: 'Index Patterns',
-      }),
-      description: i18n.translate('management.indexPatternLabel', {
-        defaultMessage:
-          'Manage the index patterns that help retrieve your data from Elasticsearch.',
-      }),
-      icon: 'indexPatternApp',
-      path: '/app/kibana#/management/kibana/index_patterns',
-      showOnHomePage: true,
-      category: FeatureCatalogueCategory.ADMIN,
-    });
+    return {
+      creation: creationManagerSetup,
+      list: this.indexPatternListConfig.setup(),
+    };
+  }
 
+  public start() {
     return {
-      creation,
-      list,
+      creation: this.indexPatternCreationManager.start(),
+      list: this.indexPatternListConfig.start(),
     };
   }
 
@@ -71,4 +63,5 @@ export class IndexPatternManagementService {
 }
 
 /** @internal */
-export type IndexPatternManagementSetup = ReturnType<IndexPatternManagementService['setup']>;
+export type IndexPatternManagementServiceSetup = ReturnType<IndexPatternManagementService['setup']>;
+export type IndexPatternManagementServiceStart = ReturnType<IndexPatternManagementService['start']>;
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/config.ts b/src/plugins/index_pattern_management/public/service/list/config.ts
similarity index 87%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/config.ts
rename to src/plugins/index_pattern_management/public/service/list/config.ts
index dd4d77a681171..87c246e8913e5 100644
--- a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/config.ts
+++ b/src/plugins/index_pattern_management/public/service/list/config.ts
@@ -33,9 +33,12 @@ export class IndexPatternListConfig {
       ? [
           {
             key: 'default',
-            name: i18n.translate('management.editIndexPattern.list.defaultIndexPatternListName', {
-              defaultMessage: 'Default',
-            }),
+            name: i18n.translate(
+              'indexPatternManagement.editIndexPattern.list.defaultIndexPatternListName',
+              {
+                defaultMessage: 'Default',
+              }
+            ),
           },
         ]
       : [];
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/index.ts b/src/plugins/index_pattern_management/public/service/list/index.ts
similarity index 100%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/index.ts
rename to src/plugins/index_pattern_management/public/service/list/index.ts
diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/manager.ts b/src/plugins/index_pattern_management/public/service/list/manager.ts
similarity index 75%
rename from src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/manager.ts
rename to src/plugins/index_pattern_management/public/service/list/manager.ts
index 73ca33ae914a9..3a2910a222cd7 100644
--- a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/list/manager.ts
+++ b/src/plugins/index_pattern_management/public/service/list/manager.ts
@@ -27,7 +27,7 @@ export class IndexPatternListManager {
     this.configs = [];
   }
 
-  public add(Config: typeof IndexPatternListConfig) {
+  private addListConfig(Config: typeof IndexPatternListConfig) {
     const config = new Config();
     if (this.configs.findIndex(c => c.key === config.key) !== -1) {
       throw new Error(`${config.key} exists in IndexPatternListManager.`);
@@ -35,7 +35,7 @@ export class IndexPatternListManager {
     this.configs.push(config);
   }
 
-  public getIndexPatternTags(indexPattern: IIndexPattern, isDefault: boolean) {
+  private getIndexPatternTags(indexPattern: IIndexPattern, isDefault: boolean) {
     return this.configs.reduce((tags: IndexPatternTag[], config) => {
       return config.getIndexPatternTags
         ? tags.concat(config.getIndexPatternTags(indexPattern, isDefault))
@@ -43,15 +43,25 @@ export class IndexPatternListManager {
     }, []);
   }
 
-  public getFieldInfo(indexPattern: IIndexPattern, field: IFieldType): string[] {
+  private getFieldInfo(indexPattern: IIndexPattern, field: IFieldType): string[] {
     return this.configs.reduce((info: string[], config) => {
       return config.getFieldInfo ? info.concat(config.getFieldInfo(indexPattern, field)) : info;
     }, []);
   }
 
-  public areScriptedFieldsEnabled(indexPattern: IIndexPattern): boolean {
+  private areScriptedFieldsEnabled(indexPattern: IIndexPattern): boolean {
     return this.configs.every(config => {
       return config.areScriptedFieldsEnabled ? config.areScriptedFieldsEnabled(indexPattern) : true;
     });
   }
+
+  setup = () => ({
+    addListConfig: this.addListConfig.bind(this),
+  });
+
+  start = () => ({
+    getIndexPatternTags: this.getIndexPatternTags.bind(this),
+    getFieldInfo: this.getFieldInfo.bind(this),
+    areScriptedFieldsEnabled: this.areScriptedFieldsEnabled.bind(this),
+  });
 }
diff --git a/x-pack/legacy/plugins/rollup/kibana.json b/x-pack/legacy/plugins/rollup/kibana.json
index 3781d59d8c0f3..3df8bd7c187d5 100644
--- a/x-pack/legacy/plugins/rollup/kibana.json
+++ b/x-pack/legacy/plugins/rollup/kibana.json
@@ -4,7 +4,8 @@
   "requiredPlugins": [
     "home",
     "index_management",
-    "metrics"
+    "metrics",
+    "indexPatternManagement"
   ],
   "optionalPlugins": [
     "usageCollection"
diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js
index f0eb21a219442..f4de2a3098127 100644
--- a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js
+++ b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js
@@ -8,7 +8,7 @@ import React from 'react';
 import { i18n } from '@kbn/i18n';
 
 import { RollupPrompt } from './components/rollup_prompt';
-import { IndexPatternCreationConfig } from '../../../../../../src/legacy/core_plugins/management/public';
+import { IndexPatternCreationConfig } from '../../../../../../src/plugins/index_pattern_management/public';
 
 const rollupIndexPatternTypeName = i18n.translate(
   'xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultTypeName',
diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js b/x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js
index fbf2612b83aa8..809a76d1868b2 100644
--- a/x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js
+++ b/x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js
@@ -3,7 +3,7 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import { IndexPatternListConfig } from '../../../../../../src/legacy/core_plugins/management/public';
+import { IndexPatternListConfig } from '../../../../../../src/plugins/index_pattern_management/public';
 
 function isRollup(indexPattern) {
   return (
diff --git a/x-pack/legacy/plugins/rollup/public/legacy.ts b/x-pack/legacy/plugins/rollup/public/legacy.ts
index ec530e63408f4..83945110c2c76 100644
--- a/x-pack/legacy/plugins/rollup/public/legacy.ts
+++ b/x-pack/legacy/plugins/rollup/public/legacy.ts
@@ -6,14 +6,8 @@
 
 import { npSetup, npStart } from 'ui/new_platform';
 import { RollupPlugin } from './plugin';
-import { setup as management } from '../../../../../src/legacy/core_plugins/management/public/legacy';
 
 const plugin = new RollupPlugin();
 
-export const setup = plugin.setup(npSetup.core, {
-  ...npSetup.plugins,
-  __LEGACY: {
-    managementLegacy: management,
-  },
-});
+export const setup = plugin.setup(npSetup.core, npSetup.plugins);
 export const start = plugin.start(npStart.core, npStart.plugins);
diff --git a/x-pack/legacy/plugins/rollup/public/plugin.ts b/x-pack/legacy/plugins/rollup/public/plugin.ts
index c58975419e20f..5782e88c3448b 100644
--- a/x-pack/legacy/plugins/rollup/public/plugin.ts
+++ b/x-pack/legacy/plugins/rollup/public/plugin.ts
@@ -7,7 +7,6 @@
 import { i18n } from '@kbn/i18n';
 import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
 import { PluginsStart } from './legacy_imports';
-import { ManagementSetup as ManagementSetupLegacy } from '../../../../../src/legacy/core_plugins/management/public/np_ready';
 import { rollupBadgeExtension, rollupToggleExtension } from './extend_index_management';
 // @ts-ignore
 import { RollupIndexPatternCreationConfig } from './index_pattern_creation/rollup_index_pattern_creation_config';
@@ -26,6 +25,7 @@ import {
 import { CRUD_APP_BASE_PATH } from './crud_app/constants';
 import { ManagementSetup } from '../../../../../src/plugins/management/public';
 import { IndexMgmtSetup } from '../../../../plugins/index_management/public';
+import { IndexPatternManagementSetup } from '../../../../../src/plugins/index_pattern_management/public';
 import { search } from '../../../../../src/plugins/data/public';
 // @ts-ignore
 import { setEsBaseAndXPackBase, setHttp } from './crud_app/services';
@@ -33,23 +33,16 @@ import { setNotifications, setFatalErrors } from './kibana_services';
 import { renderApp } from './application';
 
 export interface RollupPluginSetupDependencies {
-  __LEGACY: {
-    managementLegacy: ManagementSetupLegacy;
-  };
   home?: HomePublicPluginSetup;
   management: ManagementSetup;
   indexManagement?: IndexMgmtSetup;
+  indexPatternManagement: IndexPatternManagementSetup;
 }
 
 export class RollupPlugin implements Plugin {
   setup(
     core: CoreSetup,
-    {
-      __LEGACY: { managementLegacy },
-      home,
-      management,
-      indexManagement,
-    }: RollupPluginSetupDependencies
+    { home, management, indexManagement, indexPatternManagement }: RollupPluginSetupDependencies
   ) {
     setFatalErrors(core.fatalErrors);
 
@@ -61,8 +54,8 @@ export class RollupPlugin implements Plugin {
     const isRollupIndexPatternsEnabled = core.uiSettings.get(CONFIG_ROLLUPS);
 
     if (isRollupIndexPatternsEnabled) {
-      managementLegacy.indexPattern.creation.add(RollupIndexPatternCreationConfig);
-      managementLegacy.indexPattern.list.add(RollupIndexPatternListConfig);
+      indexPatternManagement.creation.addCreationConfig(RollupIndexPatternCreationConfig);
+      indexPatternManagement.list.addListConfig(RollupIndexPatternListConfig);
     }
 
     if (home) {
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx
index 7809b511adda4..99b4e184c071a 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx
@@ -6,7 +6,6 @@
 import React from 'react';
 import Boom from 'boom';
 import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
-import { mockManagementPlugin } from '../../../../../../src/legacy/core_plugins/management/public/np_ready/mocks';
 import { CopySavedObjectsToSpaceFlyout } from './copy_to_space_flyout';
 import { CopyToSpaceForm } from './copy_to_space_form';
 import { EuiLoadingSpinner, EuiEmptyPrompt } from '@elastic/eui';
@@ -19,11 +18,6 @@ import { spacesManagerMock } from '../../spaces_manager/mocks';
 import { SpacesManager } from '../../spaces_manager';
 import { ToastsApi } from 'src/core/public';
 
-jest.mock('../../../../../../src/legacy/core_plugins/management/public/legacy', () => ({
-  setup: mockManagementPlugin.createSetupContract(),
-  start: mockManagementPlugin.createStartContract(),
-}));
-
 interface SetupOpts {
   mockSpaces?: Space[];
   returnBeforeSpacesLoad?: boolean;
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.tsx
index 4d92505c4aebb..fee41fc7e36d3 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.tsx
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.tsx
@@ -25,7 +25,7 @@ import { ToastsStart } from 'src/core/public';
 import {
   ProcessedImportResponse,
   processImportResponse,
-} from '../../../../../../src/legacy/core_plugins/management/public';
+} from '../../../../../../src/legacy/core_plugins/kibana/public';
 import { SavedObjectsManagementRecord } from '../../../../../../src/plugins/saved_objects_management/public';
 import { Space } from '../../../common/model/space';
 import { SpacesManager } from '../../spaces_manager';
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout_footer.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout_footer.tsx
index b22cec0af5ea8..4f6ff55dbfbb2 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout_footer.tsx
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout_footer.tsx
@@ -8,7 +8,7 @@ import React, { Fragment } from 'react';
 import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiStat, EuiHorizontalRule } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { i18n } from '@kbn/i18n';
-import { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/management/public';
+import { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/kibana/public';
 import { ImportRetry } from '../types';
 
 interface Props {
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx
index 96cbac4b48065..ea74fc92b95ea 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx
@@ -13,7 +13,7 @@ import {
   EuiHorizontalRule,
 } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
-import { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/management/public';
+import { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/kibana/public';
 import { SavedObjectsManagementRecord } from '../../../../../../src/plugins/saved_objects_management/public';
 import { Space } from '../../../common/model/space';
 import { CopyOptions, ImportRetry } from '../types';
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.test.ts b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.test.ts
index fb2616619c644..65a0cabfeb716 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.test.ts
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.test.ts
@@ -5,7 +5,7 @@
  */
 
 import { summarizeCopyResult } from './summarize_copy_result';
-import { ProcessedImportResponse } from 'src/legacy/core_plugins/management/public';
+import { ProcessedImportResponse } from 'src/legacy/core_plugins/kibana/public';
 
 const createSavedObjectsManagementRecord = () => ({
   type: 'dashboard',
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.ts b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.ts
index 96e642b0f45d8..44c9e9993bf10 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.ts
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/summarize_copy_result.ts
@@ -4,7 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { ProcessedImportResponse } from 'src/legacy/core_plugins/management/public';
+import { ProcessedImportResponse } from 'src/legacy/core_plugins/kibana/public';
 import { SavedObjectsManagementRecord } from 'src/plugins/saved_objects_management/public';
 
 export interface SummarizedSavedObjectResult {
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index d07026c0883b8..00ac5b77d00f3 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -2523,12 +2523,10 @@
     "management.breadcrumb": "管理",
     "management.connectDataDisplayName": "データに接続",
     "management.displayName": "管理",
-    "management.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行",
-    "management.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン",
-    "management.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン",
-    "management.editIndexPattern.list.defaultIndexPatternListName": "デフォルト",
-    "management.indexPatternHeader": "インデックスパターン",
-    "management.indexPatternLabel": "Elasticsearch からのデータの取得に役立つインデックスパターンを管理します。",
+    "indexPatternManagement.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行",
+    "indexPatternManagement.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン",
+    "indexPatternManagement.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン",
+    "indexPatternManagement.editIndexPattern.list.defaultIndexPatternListName": "デフォルト",
     "management.nav.label": "管理",
     "management.nav.menu": "管理メニュー",
     "management.stackManagement.managementDescription": "Elastic Stack の管理を行うセンターコンソールです。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 7e64ff6301faf..f6d84431bef7f 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -2524,12 +2524,10 @@
     "management.breadcrumb": "管理",
     "management.connectDataDisplayName": "连接数据",
     "management.displayName": "管理",
-    "management.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合",
-    "management.editIndexPattern.createIndex.defaultButtonText": "标准索引模式",
-    "management.editIndexPattern.createIndex.defaultTypeName": "索引模式",
-    "management.editIndexPattern.list.defaultIndexPatternListName": "默认值",
-    "management.indexPatternHeader": "索引模式",
-    "management.indexPatternLabel": "管理帮助从 Elasticsearch 检索数据的索引模式。",
+    "indexPatternManagement.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合",
+    "indexPatternManagement.editIndexPattern.createIndex.defaultButtonText": "标准索引模式",
+    "indexPatternManagement.editIndexPattern.createIndex.defaultTypeName": "索引模式",
+    "indexPatternManagement.editIndexPattern.list.defaultIndexPatternListName": "默认值",
     "management.nav.label": "管理",
     "management.nav.menu": "管理菜单",
     "management.stackManagement.managementDescription": "您用于管理 Elastic Stack 的中心控制台。",

From fdb4a37a6016c8afce52203ecccbe03e6fc4064e Mon Sep 17 00:00:00 2001
From: Lee Drengenberg <lee.drengenberg@elastic.co>
Date: Wed, 8 Apr 2020 20:33:21 +0000
Subject: [PATCH 02/78] restore empty_kibana after saved objects test (#62951)

---
 test/functional/apps/management/_mgmt_import_saved_objects.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/functional/apps/management/_mgmt_import_saved_objects.js b/test/functional/apps/management/_mgmt_import_saved_objects.js
index 53b7e7062ee2d..2f9d9f9bfb178 100644
--- a/test/functional/apps/management/_mgmt_import_saved_objects.js
+++ b/test/functional/apps/management/_mgmt_import_saved_objects.js
@@ -35,6 +35,7 @@ export default function({ getService, getPageObjects }) {
 
     afterEach(async function() {
       await esArchiver.unload('discover');
+      await esArchiver.load('empty_kibana');
     });
 
     it('should import saved objects mgmt', async function() {

From 86a25876601053604d08ad4884db796066b819b2 Mon Sep 17 00:00:00 2001
From: Jen Huang <its.jenetic@gmail.com>
Date: Wed, 8 Apr 2020 13:33:51 -0700
Subject: [PATCH 03/78] [Ingest] Data source configuration validation UI
 (#61180)

* Initial pass at datasource configuration validation

* Show error icon and red text at input and stream levels

* Add tests, fix bugs in validation method

* Fix typings
---
 .../components/datasource_input_config.tsx    |  63 ++-
 .../components/datasource_input_panel.tsx     |  50 +-
 .../datasource_input_stream_config.tsx        |  55 +-
 .../components/datasource_input_var_field.tsx |  28 +-
 .../components/index.ts                       |   1 +
 .../create_datasource_page/index.tsx          |  16 +-
 .../create_datasource_page/services/index.ts  |   7 +
 .../services/validate_datasource.test.ts      | 504 ++++++++++++++++++
 .../services/validate_datasource.ts           | 232 ++++++++
 .../step_configure_datasource.tsx             | 169 ++++--
 .../ingest_manager/services/index.ts          |   2 +
 .../ingest_manager/types/index.ts             |   3 +
 12 files changed, 1038 insertions(+), 92 deletions(-)
 create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.test.ts
 create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.ts

diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx
index 356739af1ff9a..0e8763cb2d4c0 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx
@@ -6,26 +6,38 @@
 import React, { useState, Fragment } from 'react';
 import { FormattedMessage } from '@kbn/i18n/react';
 import {
-  EuiFlexGrid,
   EuiFlexGroup,
   EuiFlexItem,
   EuiText,
+  EuiTextColor,
   EuiSpacer,
   EuiButtonEmpty,
   EuiTitle,
+  EuiIconTip,
 } from '@elastic/eui';
 import { DatasourceInput, RegistryVarsEntry } from '../../../../types';
-import { isAdvancedVar } from '../services';
+import { isAdvancedVar, DatasourceConfigValidationResults, validationHasErrors } from '../services';
 import { DatasourceInputVarField } from './datasource_input_var_field';
 
 export const DatasourceInputConfig: React.FunctionComponent<{
   packageInputVars?: RegistryVarsEntry[];
   datasourceInput: DatasourceInput;
   updateDatasourceInput: (updatedInput: Partial<DatasourceInput>) => void;
-}> = ({ packageInputVars, datasourceInput, updateDatasourceInput }) => {
+  inputVarsValidationResults: DatasourceConfigValidationResults;
+  forceShowErrors?: boolean;
+}> = ({
+  packageInputVars,
+  datasourceInput,
+  updateDatasourceInput,
+  inputVarsValidationResults,
+  forceShowErrors,
+}) => {
   // Showing advanced options toggle state
   const [isShowingAdvanced, setIsShowingAdvanced] = useState<boolean>(false);
 
+  // Errors state
+  const hasErrors = forceShowErrors && validationHasErrors(inputVarsValidationResults);
+
   const requiredVars: RegistryVarsEntry[] = [];
   const advancedVars: RegistryVarsEntry[] = [];
 
@@ -40,15 +52,36 @@ export const DatasourceInputConfig: React.FunctionComponent<{
   }
 
   return (
-    <EuiFlexGrid columns={2}>
-      <EuiFlexItem>
+    <EuiFlexGroup alignItems="flexStart">
+      <EuiFlexItem grow={1}>
         <EuiTitle size="s">
-          <h4>
-            <FormattedMessage
-              id="xpack.ingestManager.createDatasource.stepConfigure.inputSettingsTitle"
-              defaultMessage="Settings"
-            />
-          </h4>
+          <EuiFlexGroup alignItems="center" gutterSize="s">
+            <EuiFlexItem grow={false}>
+              <h4>
+                <EuiTextColor color={hasErrors ? 'danger' : 'default'}>
+                  <FormattedMessage
+                    id="xpack.ingestManager.createDatasource.stepConfigure.inputSettingsTitle"
+                    defaultMessage="Settings"
+                  />
+                </EuiTextColor>
+              </h4>
+            </EuiFlexItem>
+            {hasErrors ? (
+              <EuiFlexItem grow={false}>
+                <EuiIconTip
+                  content={
+                    <FormattedMessage
+                      id="xpack.ingestManager.createDatasource.stepConfigure.inputConfigErrorsTooltip"
+                      defaultMessage="Fix configuration errors"
+                    />
+                  }
+                  position="right"
+                  type="alert"
+                  iconProps={{ color: 'danger' }}
+                />
+              </EuiFlexItem>
+            ) : null}
+          </EuiFlexGroup>
         </EuiTitle>
         <EuiSpacer size="m" />
         <EuiText color="subdued" size="s">
@@ -60,7 +93,7 @@ export const DatasourceInputConfig: React.FunctionComponent<{
           </p>
         </EuiText>
       </EuiFlexItem>
-      <EuiFlexItem>
+      <EuiFlexItem grow={1}>
         <EuiFlexGroup direction="column" gutterSize="m">
           {requiredVars.map(varDef => {
             const { name: varName, type: varType } = varDef;
@@ -81,6 +114,8 @@ export const DatasourceInputConfig: React.FunctionComponent<{
                       },
                     });
                   }}
+                  errors={inputVarsValidationResults.config![varName]}
+                  forceShowErrors={forceShowErrors}
                 />
               </EuiFlexItem>
             );
@@ -123,6 +158,8 @@ export const DatasourceInputConfig: React.FunctionComponent<{
                               },
                             });
                           }}
+                          errors={inputVarsValidationResults.config![varName]}
+                          forceShowErrors={forceShowErrors}
                         />
                       </EuiFlexItem>
                     );
@@ -132,6 +169,6 @@ export const DatasourceInputConfig: React.FunctionComponent<{
           ) : null}
         </EuiFlexGroup>
       </EuiFlexItem>
-    </EuiFlexGrid>
+    </EuiFlexGroup>
   );
 };
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_panel.tsx
index 74b08f48df12d..6b0c68ccb7d3f 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_panel.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_panel.tsx
@@ -17,8 +17,10 @@ import {
   EuiButtonIcon,
   EuiHorizontalRule,
   EuiSpacer,
+  EuiIconTip,
 } from '@elastic/eui';
 import { DatasourceInput, DatasourceInputStream, RegistryInput } from '../../../../types';
+import { DatasourceInputValidationResults, validationHasErrors } from '../services';
 import { DatasourceInputConfig } from './datasource_input_config';
 import { DatasourceInputStreamConfig } from './datasource_input_stream_config';
 
@@ -32,10 +34,21 @@ export const DatasourceInputPanel: React.FunctionComponent<{
   packageInput: RegistryInput;
   datasourceInput: DatasourceInput;
   updateDatasourceInput: (updatedInput: Partial<DatasourceInput>) => void;
-}> = ({ packageInput, datasourceInput, updateDatasourceInput }) => {
+  inputValidationResults: DatasourceInputValidationResults;
+  forceShowErrors?: boolean;
+}> = ({
+  packageInput,
+  datasourceInput,
+  updateDatasourceInput,
+  inputValidationResults,
+  forceShowErrors,
+}) => {
   // Showing streams toggle state
   const [isShowingStreams, setIsShowingStreams] = useState<boolean>(false);
 
+  // Errors state
+  const hasErrors = forceShowErrors && validationHasErrors(inputValidationResults);
+
   return (
     <EuiPanel>
       {/* Header / input-level toggle */}
@@ -43,9 +56,32 @@ export const DatasourceInputPanel: React.FunctionComponent<{
         <EuiFlexItem grow={false}>
           <EuiSwitch
             label={
-              <EuiText>
-                <h4>{packageInput.title || packageInput.type}</h4>
-              </EuiText>
+              <EuiFlexGroup alignItems="center" gutterSize="s">
+                <EuiFlexItem grow={false}>
+                  <EuiText>
+                    <h4>
+                      <EuiTextColor color={hasErrors ? 'danger' : 'default'}>
+                        {packageInput.title || packageInput.type}
+                      </EuiTextColor>
+                    </h4>
+                  </EuiText>
+                </EuiFlexItem>
+                {hasErrors ? (
+                  <EuiFlexItem grow={false}>
+                    <EuiIconTip
+                      content={
+                        <FormattedMessage
+                          id="xpack.ingestManager.createDatasource.stepConfigure.inputLevelErrorsTooltip"
+                          defaultMessage="Fix configuration errors"
+                        />
+                      }
+                      position="right"
+                      type="alert"
+                      iconProps={{ color: 'danger' }}
+                    />
+                  </EuiFlexItem>
+                ) : null}
+              </EuiFlexGroup>
             }
             checked={datasourceInput.enabled}
             onChange={e => {
@@ -122,6 +158,8 @@ export const DatasourceInputPanel: React.FunctionComponent<{
             packageInputVars={packageInput.vars}
             datasourceInput={datasourceInput}
             updateDatasourceInput={updateDatasourceInput}
+            inputVarsValidationResults={{ config: inputValidationResults.config }}
+            forceShowErrors={forceShowErrors}
           />
           <EuiHorizontalRule margin="m" />
         </Fragment>
@@ -165,6 +203,10 @@ export const DatasourceInputPanel: React.FunctionComponent<{
 
                     updateDatasourceInput(updatedInput);
                   }}
+                  inputStreamValidationResults={
+                    inputValidationResults.streams![datasourceInputStream.id]
+                  }
+                  forceShowErrors={forceShowErrors}
                 />
                 <EuiSpacer size="m" />
                 <EuiHorizontalRule margin="none" />
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_stream_config.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_stream_config.tsx
index 3bf5b2bb4c0f0..43e8f5a2c060d 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_stream_config.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_stream_config.tsx
@@ -7,26 +7,38 @@ import React, { useState, Fragment } from 'react';
 import ReactMarkdown from 'react-markdown';
 import { FormattedMessage } from '@kbn/i18n/react';
 import {
-  EuiFlexGrid,
   EuiFlexGroup,
   EuiFlexItem,
   EuiSwitch,
   EuiText,
   EuiSpacer,
   EuiButtonEmpty,
+  EuiTextColor,
+  EuiIconTip,
 } from '@elastic/eui';
 import { DatasourceInputStream, RegistryStream, RegistryVarsEntry } from '../../../../types';
-import { isAdvancedVar } from '../services';
+import { isAdvancedVar, DatasourceConfigValidationResults, validationHasErrors } from '../services';
 import { DatasourceInputVarField } from './datasource_input_var_field';
 
 export const DatasourceInputStreamConfig: React.FunctionComponent<{
   packageInputStream: RegistryStream;
   datasourceInputStream: DatasourceInputStream;
   updateDatasourceInputStream: (updatedStream: Partial<DatasourceInputStream>) => void;
-}> = ({ packageInputStream, datasourceInputStream, updateDatasourceInputStream }) => {
+  inputStreamValidationResults: DatasourceConfigValidationResults;
+  forceShowErrors?: boolean;
+}> = ({
+  packageInputStream,
+  datasourceInputStream,
+  updateDatasourceInputStream,
+  inputStreamValidationResults,
+  forceShowErrors,
+}) => {
   // Showing advanced options toggle state
   const [isShowingAdvanced, setIsShowingAdvanced] = useState<boolean>(false);
 
+  // Errors state
+  const hasErrors = forceShowErrors && validationHasErrors(inputStreamValidationResults);
+
   const requiredVars: RegistryVarsEntry[] = [];
   const advancedVars: RegistryVarsEntry[] = [];
 
@@ -41,10 +53,33 @@ export const DatasourceInputStreamConfig: React.FunctionComponent<{
   }
 
   return (
-    <EuiFlexGrid columns={2}>
-      <EuiFlexItem>
+    <EuiFlexGroup>
+      <EuiFlexItem grow={1}>
         <EuiSwitch
-          label={packageInputStream.title || packageInputStream.dataset}
+          label={
+            <EuiFlexGroup alignItems="center" gutterSize="s">
+              <EuiFlexItem grow={false}>
+                <EuiTextColor color={hasErrors ? 'danger' : 'default'}>
+                  {packageInputStream.title || packageInputStream.dataset}
+                </EuiTextColor>
+              </EuiFlexItem>
+              {hasErrors ? (
+                <EuiFlexItem grow={false}>
+                  <EuiIconTip
+                    content={
+                      <FormattedMessage
+                        id="xpack.ingestManager.createDatasource.stepConfigure.streamLevelErrorsTooltip"
+                        defaultMessage="Fix configuration errors"
+                      />
+                    }
+                    position="right"
+                    type="alert"
+                    iconProps={{ color: 'danger' }}
+                  />
+                </EuiFlexItem>
+              ) : null}
+            </EuiFlexGroup>
+          }
           checked={datasourceInputStream.enabled}
           onChange={e => {
             const enabled = e.target.checked;
@@ -62,7 +97,7 @@ export const DatasourceInputStreamConfig: React.FunctionComponent<{
           </Fragment>
         ) : null}
       </EuiFlexItem>
-      <EuiFlexItem>
+      <EuiFlexItem grow={1}>
         <EuiFlexGroup direction="column" gutterSize="m">
           {requiredVars.map(varDef => {
             const { name: varName, type: varType } = varDef;
@@ -83,6 +118,8 @@ export const DatasourceInputStreamConfig: React.FunctionComponent<{
                       },
                     });
                   }}
+                  errors={inputStreamValidationResults.config![varName]}
+                  forceShowErrors={forceShowErrors}
                 />
               </EuiFlexItem>
             );
@@ -125,6 +162,8 @@ export const DatasourceInputStreamConfig: React.FunctionComponent<{
                               },
                             });
                           }}
+                          errors={inputStreamValidationResults.config![varName]}
+                          forceShowErrors={forceShowErrors}
                         />
                       </EuiFlexItem>
                     );
@@ -134,6 +173,6 @@ export const DatasourceInputStreamConfig: React.FunctionComponent<{
           ) : null}
         </EuiFlexGroup>
       </EuiFlexItem>
-    </EuiFlexGrid>
+    </EuiFlexGroup>
   );
 };
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_var_field.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_var_field.tsx
index bcb99eed88ac0..846a807f9240d 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_var_field.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_var_field.tsx
@@ -3,7 +3,7 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React from 'react';
+import React, { useState } from 'react';
 import ReactMarkdown from 'react-markdown';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { EuiFormRow, EuiFieldText, EuiComboBox, EuiText, EuiCodeEditor } from '@elastic/eui';
@@ -16,12 +16,20 @@ export const DatasourceInputVarField: React.FunctionComponent<{
   varDef: RegistryVarsEntry;
   value: any;
   onChange: (newValue: any) => void;
-}> = ({ varDef, value, onChange }) => {
+  errors?: string[] | null;
+  forceShowErrors?: boolean;
+}> = ({ varDef, value, onChange, errors: varErrors, forceShowErrors }) => {
+  const [isDirty, setIsDirty] = useState<boolean>(false);
+  const { multi, required, type, title, name, description } = varDef;
+  const isInvalid = (isDirty || forceShowErrors) && !!varErrors;
+  const errors = isInvalid ? varErrors : null;
+
   const renderField = () => {
-    if (varDef.multi) {
+    if (multi) {
       return (
         <EuiComboBox
           noSuggestions
+          isInvalid={isInvalid}
           selectedOptions={value.map((val: string) => ({ label: val }))}
           onCreateOption={(newVal: any) => {
             onChange([...value, newVal]);
@@ -29,10 +37,11 @@ export const DatasourceInputVarField: React.FunctionComponent<{
           onChange={(newVals: any[]) => {
             onChange(newVals.map(val => val.label));
           }}
+          onBlur={() => setIsDirty(true)}
         />
       );
     }
-    if (varDef.type === 'yaml') {
+    if (type === 'yaml') {
       return (
         <EuiCodeEditor
           width="100%"
@@ -46,22 +55,27 @@ export const DatasourceInputVarField: React.FunctionComponent<{
           }}
           value={value}
           onChange={newVal => onChange(newVal)}
+          onBlur={() => setIsDirty(true)}
         />
       );
     }
     return (
       <EuiFieldText
+        isInvalid={isInvalid}
         value={value === undefined ? '' : value}
         onChange={e => onChange(e.target.value)}
+        onBlur={() => setIsDirty(true)}
       />
     );
   };
 
   return (
     <EuiFormRow
-      label={varDef.title || varDef.name}
+      isInvalid={isInvalid}
+      error={errors}
+      label={title || name}
       labelAppend={
-        !varDef.required ? (
+        !required ? (
           <EuiText size="xs" color="subdued">
             <FormattedMessage
               id="xpack.ingestManager.createDatasource.stepConfigure.inputVarFieldOptionalLabel"
@@ -70,7 +84,7 @@ export const DatasourceInputVarField: React.FunctionComponent<{
           </EuiText>
         ) : null
       }
-      helpText={<ReactMarkdown source={varDef.description} />}
+      helpText={<ReactMarkdown source={description} />}
     >
       {renderField()}
     </EuiFormRow>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts
index e5f18e1449d1b..3bfca75668911 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts
@@ -5,3 +5,4 @@
  */
 export { CreateDatasourcePageLayout } from './layout';
 export { DatasourceInputPanel } from './datasource_input_panel';
+export { DatasourceInputVarField } from './datasource_input_var_field';
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
index 23d0f3317a667..7815ab9cd1d6e 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
@@ -21,6 +21,7 @@ import { useLinks as useEPMLinks } from '../../epm/hooks';
 import { CreateDatasourcePageLayout } from './components';
 import { CreateDatasourceFrom, CreateDatasourceStep } from './types';
 import { CREATE_DATASOURCE_STEP_PATHS } from './constants';
+import { DatasourceValidationResults, validateDatasource } from './services';
 import { StepSelectPackage } from './step_select_package';
 import { StepSelectConfig } from './step_select_config';
 import { StepConfigureDatasource } from './step_configure_datasource';
@@ -51,6 +52,9 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
     inputs: [],
   });
 
+  // Datasource validation state
+  const [validationResults, setValidationResults] = useState<DatasourceValidationResults>();
+
   // Update package info method
   const updatePackageInfo = (updatedPackageInfo: PackageInfo | undefined) => {
     if (updatedPackageInfo) {
@@ -84,9 +88,18 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
       ...updatedFields,
     };
     setDatasource(newDatasource);
-
     // eslint-disable-next-line no-console
     console.debug('Datasource updated', newDatasource);
+    updateDatasourceValidation(newDatasource);
+  };
+
+  const updateDatasourceValidation = (newDatasource?: NewDatasource) => {
+    if (packageInfo) {
+      const newValidationResult = validateDatasource(newDatasource || datasource, packageInfo);
+      setValidationResults(newValidationResult);
+      // eslint-disable-next-line no-console
+      console.debug('Datasource validation results', newValidationResult);
+    }
   };
 
   // Cancel url
@@ -202,6 +215,7 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
                 packageInfo={packageInfo}
                 datasource={datasource}
                 updateDatasource={updateDatasource}
+                validationResults={validationResults!}
                 backLink={
                   <EuiButtonEmpty href={firstStepUrl} iconType="arrowLeft" iconSide="left">
                     {from === 'config' ? (
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/index.ts
index 44e5bfa41cb9b..d99f0712db3c3 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/index.ts
@@ -4,3 +4,10 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 export { isAdvancedVar } from './is_advanced_var';
+export {
+  DatasourceValidationResults,
+  DatasourceConfigValidationResults,
+  DatasourceInputValidationResults,
+  validateDatasource,
+  validationHasErrors,
+} from './validate_datasource';
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.test.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.test.ts
new file mode 100644
index 0000000000000..a45fabeb5ed6a
--- /dev/null
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.test.ts
@@ -0,0 +1,504 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import {
+  PackageInfo,
+  InstallationStatus,
+  NewDatasource,
+  RegistryDatasource,
+} from '../../../../types';
+import { validateDatasource, validationHasErrors } from './validate_datasource';
+
+describe('Ingest Manager - validateDatasource()', () => {
+  const mockPackage = ({
+    name: 'mock-package',
+    title: 'Mock package',
+    version: '0.0.0',
+    description: 'description',
+    type: 'mock',
+    categories: [],
+    requirement: { kibana: { versions: '' }, elasticsearch: { versions: '' } },
+    format_version: '',
+    download: '',
+    path: '',
+    assets: {
+      kibana: {
+        dashboard: [],
+        visualization: [],
+        search: [],
+        'index-pattern': [],
+      },
+    },
+    status: InstallationStatus.notInstalled,
+    datasources: [
+      {
+        name: 'datasource1',
+        title: 'Datasource 1',
+        description: 'test datasource',
+        inputs: [
+          {
+            type: 'foo',
+            title: 'Foo',
+            vars: [
+              { default: 'foo-input-var-value', name: 'foo-input-var-name', type: 'text' },
+              {
+                default: 'foo-input2-var-value',
+                name: 'foo-input2-var-name',
+                required: true,
+                type: 'text',
+              },
+              { name: 'foo-input3-var-name', type: 'text', required: true, multi: true },
+            ],
+            streams: [
+              {
+                dataset: 'foo',
+                input: 'foo',
+                title: 'Foo',
+                vars: [{ name: 'var-name', type: 'yaml' }],
+              },
+            ],
+          },
+          {
+            type: 'bar',
+            title: 'Bar',
+            vars: [
+              {
+                default: ['value1', 'value2'],
+                name: 'bar-input-var-name',
+                type: 'text',
+                multi: true,
+              },
+              { name: 'bar-input2-var-name', required: true, type: 'text' },
+            ],
+            streams: [
+              {
+                dataset: 'bar',
+                input: 'bar',
+                title: 'Bar',
+                vars: [{ name: 'var-name', type: 'yaml', required: true }],
+              },
+              {
+                dataset: 'bar2',
+                input: 'bar2',
+                title: 'Bar 2',
+                vars: [{ default: 'bar2-var-value', name: 'var-name', type: 'text' }],
+              },
+            ],
+          },
+          {
+            type: 'with-no-config-or-streams',
+            title: 'With no config or streams',
+            streams: [],
+          },
+          {
+            type: 'with-disabled-streams',
+            title: 'With disabled streams',
+            streams: [
+              {
+                dataset: 'disabled',
+                input: 'disabled',
+                title: 'Disabled',
+                enabled: false,
+                vars: [{ multi: true, required: true, name: 'var-name', type: 'text' }],
+              },
+              { dataset: 'disabled2', input: 'disabled2', title: 'Disabled 2', enabled: false },
+            ],
+          },
+        ],
+      },
+    ],
+  } as unknown) as PackageInfo;
+
+  const validDatasource: NewDatasource = {
+    name: 'datasource1-1',
+    config_id: 'test-config',
+    enabled: true,
+    output_id: 'test-output',
+    inputs: [
+      {
+        type: 'foo',
+        enabled: true,
+        config: {
+          'foo-input-var-name': { value: 'foo-input-var-value', type: 'text' },
+          'foo-input2-var-name': { value: 'foo-input2-var-value', type: 'text' },
+          'foo-input3-var-name': { value: ['test'], type: 'text' },
+        },
+        streams: [
+          {
+            id: 'foo-foo',
+            dataset: 'foo',
+            enabled: true,
+            config: { 'var-name': { value: 'test_yaml: value', type: 'yaml' } },
+          },
+        ],
+      },
+      {
+        type: 'bar',
+        enabled: true,
+        config: {
+          'bar-input-var-name': { value: ['value1', 'value2'], type: 'text' },
+          'bar-input2-var-name': { value: 'test', type: 'text' },
+        },
+        streams: [
+          {
+            id: 'bar-bar',
+            dataset: 'bar',
+            enabled: true,
+            config: { 'var-name': { value: 'test_yaml: value', type: 'yaml' } },
+          },
+          {
+            id: 'bar-bar2',
+            dataset: 'bar2',
+            enabled: true,
+            config: { 'var-name': { value: undefined, type: 'text' } },
+          },
+        ],
+      },
+      {
+        type: 'with-no-config-or-streams',
+        enabled: true,
+        streams: [],
+      },
+      {
+        type: 'with-disabled-streams',
+        enabled: true,
+        streams: [
+          {
+            id: 'with-disabled-streams-disabled',
+            dataset: 'disabled',
+            enabled: false,
+            config: { 'var-name': { value: undefined, type: 'text' } },
+          },
+          {
+            id: 'with-disabled-streams-disabled2',
+            dataset: 'disabled2',
+            enabled: false,
+          },
+        ],
+      },
+    ],
+  };
+
+  const invalidDatasource: NewDatasource = {
+    ...validDatasource,
+    name: '',
+    inputs: [
+      {
+        type: 'foo',
+        enabled: true,
+        config: {
+          'foo-input-var-name': { value: undefined, type: 'text' },
+          'foo-input2-var-name': { value: '', type: 'text' },
+          'foo-input3-var-name': { value: [], type: 'text' },
+        },
+        streams: [
+          {
+            id: 'foo-foo',
+            dataset: 'foo',
+            enabled: true,
+            config: { 'var-name': { value: 'invalidyaml: test\n foo bar:', type: 'yaml' } },
+          },
+        ],
+      },
+      {
+        type: 'bar',
+        enabled: true,
+        config: {
+          'bar-input-var-name': { value: 'invalid value for multi', type: 'text' },
+          'bar-input2-var-name': { value: undefined, type: 'text' },
+        },
+        streams: [
+          {
+            id: 'bar-bar',
+            dataset: 'bar',
+            enabled: true,
+            config: { 'var-name': { value: '    \n\n', type: 'yaml' } },
+          },
+          {
+            id: 'bar-bar2',
+            dataset: 'bar2',
+            enabled: true,
+            config: { 'var-name': { value: undefined, type: 'text' } },
+          },
+        ],
+      },
+      {
+        type: 'with-no-config-or-streams',
+        enabled: true,
+        streams: [],
+      },
+      {
+        type: 'with-disabled-streams',
+        enabled: true,
+        streams: [
+          {
+            id: 'with-disabled-streams-disabled',
+            dataset: 'disabled',
+            enabled: false,
+            config: {
+              'var-name': {
+                value: 'invalid value but not checked due to not enabled',
+                type: 'text',
+              },
+            },
+          },
+          {
+            id: 'with-disabled-streams-disabled2',
+            dataset: 'disabled2',
+            enabled: false,
+          },
+        ],
+      },
+    ],
+  };
+
+  const noErrorsValidationResults = {
+    name: null,
+    description: null,
+    inputs: {
+      foo: {
+        config: {
+          'foo-input-var-name': null,
+          'foo-input2-var-name': null,
+          'foo-input3-var-name': null,
+        },
+        streams: { 'foo-foo': { config: { 'var-name': null } } },
+      },
+      bar: {
+        config: { 'bar-input-var-name': null, 'bar-input2-var-name': null },
+        streams: {
+          'bar-bar': { config: { 'var-name': null } },
+          'bar-bar2': { config: { 'var-name': null } },
+        },
+      },
+      'with-disabled-streams': {
+        streams: { 'with-disabled-streams-disabled': { config: { 'var-name': null } } },
+      },
+    },
+  };
+
+  it('returns no errors for valid datasource configuration', () => {
+    expect(validateDatasource(validDatasource, mockPackage)).toEqual(noErrorsValidationResults);
+  });
+
+  it('returns errors for invalid datasource configuration', () => {
+    expect(validateDatasource(invalidDatasource, mockPackage)).toEqual({
+      name: ['Name is required'],
+      description: null,
+      inputs: {
+        foo: {
+          config: {
+            'foo-input-var-name': null,
+            'foo-input2-var-name': ['foo-input2-var-name is required'],
+            'foo-input3-var-name': ['foo-input3-var-name is required'],
+          },
+          streams: { 'foo-foo': { config: { 'var-name': ['Invalid YAML format'] } } },
+        },
+        bar: {
+          config: {
+            'bar-input-var-name': ['Invalid format'],
+            'bar-input2-var-name': ['bar-input2-var-name is required'],
+          },
+          streams: {
+            'bar-bar': { config: { 'var-name': ['var-name is required'] } },
+            'bar-bar2': { config: { 'var-name': null } },
+          },
+        },
+        'with-disabled-streams': {
+          streams: { 'with-disabled-streams-disabled': { config: { 'var-name': null } } },
+        },
+      },
+    });
+  });
+
+  it('returns no errors for disabled inputs', () => {
+    const disabledInputs = invalidDatasource.inputs.map(input => ({ ...input, enabled: false }));
+    expect(validateDatasource({ ...validDatasource, inputs: disabledInputs }, mockPackage)).toEqual(
+      noErrorsValidationResults
+    );
+  });
+
+  it('returns only datasource and input-level errors for disabled streams', () => {
+    const inputsWithDisabledStreams = invalidDatasource.inputs.map(input =>
+      input.streams
+        ? {
+            ...input,
+            streams: input.streams.map(stream => ({ ...stream, enabled: false })),
+          }
+        : input
+    );
+    expect(
+      validateDatasource({ ...invalidDatasource, inputs: inputsWithDisabledStreams }, mockPackage)
+    ).toEqual({
+      name: ['Name is required'],
+      description: null,
+      inputs: {
+        foo: {
+          config: {
+            'foo-input-var-name': null,
+            'foo-input2-var-name': ['foo-input2-var-name is required'],
+            'foo-input3-var-name': ['foo-input3-var-name is required'],
+          },
+          streams: { 'foo-foo': { config: { 'var-name': null } } },
+        },
+        bar: {
+          config: {
+            'bar-input-var-name': ['Invalid format'],
+            'bar-input2-var-name': ['bar-input2-var-name is required'],
+          },
+          streams: {
+            'bar-bar': { config: { 'var-name': null } },
+            'bar-bar2': { config: { 'var-name': null } },
+          },
+        },
+        'with-disabled-streams': {
+          streams: { 'with-disabled-streams-disabled': { config: { 'var-name': null } } },
+        },
+      },
+    });
+  });
+
+  it('returns no errors for packages with no datasources', () => {
+    expect(
+      validateDatasource(validDatasource, {
+        ...mockPackage,
+        datasources: undefined,
+      })
+    ).toEqual({
+      name: null,
+      description: null,
+      inputs: null,
+    });
+    expect(
+      validateDatasource(validDatasource, {
+        ...mockPackage,
+        datasources: [],
+      })
+    ).toEqual({
+      name: null,
+      description: null,
+      inputs: null,
+    });
+  });
+
+  it('returns no errors for packages with no inputs', () => {
+    expect(
+      validateDatasource(validDatasource, {
+        ...mockPackage,
+        datasources: [{} as RegistryDatasource],
+      })
+    ).toEqual({
+      name: null,
+      description: null,
+      inputs: null,
+    });
+    expect(
+      validateDatasource(validDatasource, {
+        ...mockPackage,
+        datasources: [({ inputs: [] } as unknown) as RegistryDatasource],
+      })
+    ).toEqual({
+      name: null,
+      description: null,
+      inputs: null,
+    });
+  });
+});
+
+describe('Ingest Manager - validationHasErrors()', () => {
+  it('returns true for stream validation results with errors', () => {
+    expect(
+      validationHasErrors({
+        config: { foo: ['foo error'], bar: null },
+      })
+    ).toBe(true);
+  });
+
+  it('returns false for stream validation results with no errors', () => {
+    expect(
+      validationHasErrors({
+        config: { foo: null, bar: null },
+      })
+    ).toBe(false);
+  });
+
+  it('returns true for input validation results with errors', () => {
+    expect(
+      validationHasErrors({
+        config: { foo: ['foo error'], bar: null },
+        streams: { stream1: { config: { foo: null, bar: null } } },
+      })
+    ).toBe(true);
+    expect(
+      validationHasErrors({
+        config: { foo: null, bar: null },
+        streams: { stream1: { config: { foo: ['foo error'], bar: null } } },
+      })
+    ).toBe(true);
+  });
+
+  it('returns false for input validation results with no errors', () => {
+    expect(
+      validationHasErrors({
+        config: { foo: null, bar: null },
+        streams: { stream1: { config: { foo: null, bar: null } } },
+      })
+    ).toBe(false);
+  });
+
+  it('returns true for datasource validation results with errors', () => {
+    expect(
+      validationHasErrors({
+        name: ['name error'],
+        description: null,
+        inputs: {
+          input1: {
+            config: { foo: null, bar: null },
+            streams: { stream1: { config: { foo: null, bar: null } } },
+          },
+        },
+      })
+    ).toBe(true);
+    expect(
+      validationHasErrors({
+        name: null,
+        description: null,
+        inputs: {
+          input1: {
+            config: { foo: ['foo error'], bar: null },
+            streams: { stream1: { config: { foo: null, bar: null } } },
+          },
+        },
+      })
+    ).toBe(true);
+    expect(
+      validationHasErrors({
+        name: null,
+        description: null,
+        inputs: {
+          input1: {
+            config: { foo: null, bar: null },
+            streams: { stream1: { config: { foo: ['foo error'], bar: null } } },
+          },
+        },
+      })
+    ).toBe(true);
+  });
+
+  it('returns false for datasource validation results with no errors', () => {
+    expect(
+      validationHasErrors({
+        name: null,
+        description: null,
+        inputs: {
+          input1: {
+            config: { foo: null, bar: null },
+            streams: { stream1: { config: { foo: null, bar: null } } },
+          },
+        },
+      })
+    ).toBe(false);
+  });
+});
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.ts
new file mode 100644
index 0000000000000..518e2bfc1af07
--- /dev/null
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/services/validate_datasource.ts
@@ -0,0 +1,232 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import { i18n } from '@kbn/i18n';
+import { safeLoad } from 'js-yaml';
+import { getFlattenedObject } from '../../../../services';
+import {
+  NewDatasource,
+  DatasourceInput,
+  DatasourceInputStream,
+  DatasourceConfigRecordEntry,
+  PackageInfo,
+  RegistryInput,
+  RegistryVarsEntry,
+} from '../../../../types';
+
+type Errors = string[] | null;
+
+type ValidationEntry = Record<string, Errors>;
+
+export interface DatasourceConfigValidationResults {
+  config?: ValidationEntry;
+}
+
+export type DatasourceInputValidationResults = DatasourceConfigValidationResults & {
+  streams?: Record<DatasourceInputStream['id'], DatasourceConfigValidationResults>;
+};
+
+export interface DatasourceValidationResults {
+  name: Errors;
+  description: Errors;
+  inputs: Record<DatasourceInput['type'], DatasourceInputValidationResults> | null;
+}
+
+/*
+ * Returns validation information for a given datasource configuration and package info
+ * Note: this method assumes that `datasource` is correctly structured for the given package
+ */
+export const validateDatasource = (
+  datasource: NewDatasource,
+  packageInfo: PackageInfo
+): DatasourceValidationResults => {
+  const validationResults: DatasourceValidationResults = {
+    name: null,
+    description: null,
+    inputs: {},
+  };
+
+  if (!datasource.name.trim()) {
+    validationResults.name = [
+      i18n.translate('xpack.ingestManager.datasourceValidation.nameRequiredErrorMessage', {
+        defaultMessage: 'Name is required',
+      }),
+    ];
+  }
+
+  if (
+    !packageInfo.datasources ||
+    packageInfo.datasources.length === 0 ||
+    !packageInfo.datasources[0] ||
+    !packageInfo.datasources[0].inputs ||
+    packageInfo.datasources[0].inputs.length === 0
+  ) {
+    validationResults.inputs = null;
+    return validationResults;
+  }
+
+  const registryInputsByType: Record<
+    string,
+    RegistryInput
+  > = packageInfo.datasources[0].inputs.reduce((inputs, registryInput) => {
+    inputs[registryInput.type] = registryInput;
+    return inputs;
+  }, {} as Record<string, RegistryInput>);
+
+  // Validate each datasource input with either its own config fields or streams
+  datasource.inputs.forEach(input => {
+    if (!input.config && !input.streams) {
+      return;
+    }
+
+    const inputValidationResults: DatasourceInputValidationResults = {
+      config: undefined,
+      streams: {},
+    };
+
+    const inputVarsByName = (registryInputsByType[input.type].vars || []).reduce(
+      (vars, registryVar) => {
+        vars[registryVar.name] = registryVar;
+        return vars;
+      },
+      {} as Record<string, RegistryVarsEntry>
+    );
+
+    // Validate input-level config fields
+    const inputConfigs = Object.entries(input.config || {});
+    if (inputConfigs.length) {
+      inputValidationResults.config = inputConfigs.reduce((results, [name, configEntry]) => {
+        results[name] = input.enabled
+          ? validateDatasourceConfig(configEntry, inputVarsByName[name])
+          : null;
+        return results;
+      }, {} as ValidationEntry);
+    } else {
+      delete inputValidationResults.config;
+    }
+
+    // Validate each input stream with config fields
+    if (input.streams.length) {
+      input.streams.forEach(stream => {
+        if (!stream.config) {
+          return;
+        }
+
+        const streamValidationResults: DatasourceConfigValidationResults = {
+          config: undefined,
+        };
+
+        const streamVarsByName = (
+          (
+            registryInputsByType[input.type].streams.find(
+              registryStream => registryStream.dataset === stream.dataset
+            ) || {}
+          ).vars || []
+        ).reduce((vars, registryVar) => {
+          vars[registryVar.name] = registryVar;
+          return vars;
+        }, {} as Record<string, RegistryVarsEntry>);
+
+        // Validate stream-level config fields
+        streamValidationResults.config = Object.entries(stream.config).reduce(
+          (results, [name, configEntry]) => {
+            results[name] =
+              input.enabled && stream.enabled
+                ? validateDatasourceConfig(configEntry, streamVarsByName[name])
+                : null;
+            return results;
+          },
+          {} as ValidationEntry
+        );
+
+        inputValidationResults.streams![stream.id] = streamValidationResults;
+      });
+    } else {
+      delete inputValidationResults.streams;
+    }
+
+    if (inputValidationResults.config || inputValidationResults.streams) {
+      validationResults.inputs![input.type] = inputValidationResults;
+    }
+  });
+
+  if (Object.entries(validationResults.inputs!).length === 0) {
+    validationResults.inputs = null;
+  }
+  return validationResults;
+};
+
+const validateDatasourceConfig = (
+  configEntry: DatasourceConfigRecordEntry,
+  varDef: RegistryVarsEntry
+): string[] | null => {
+  const errors = [];
+  const { value } = configEntry;
+  let parsedValue: any = value;
+
+  if (typeof value === 'string') {
+    parsedValue = value.trim();
+  }
+
+  if (varDef.required) {
+    if (parsedValue === undefined || (typeof parsedValue === 'string' && !parsedValue)) {
+      errors.push(
+        i18n.translate('xpack.ingestManager.datasourceValidation.requiredErrorMessage', {
+          defaultMessage: '{fieldName} is required',
+          values: {
+            fieldName: varDef.title || varDef.name,
+          },
+        })
+      );
+    }
+  }
+
+  if (varDef.type === 'yaml') {
+    try {
+      parsedValue = safeLoad(value);
+    } catch (e) {
+      errors.push(
+        i18n.translate('xpack.ingestManager.datasourceValidation.invalidYamlFormatErrorMessage', {
+          defaultMessage: 'Invalid YAML format',
+        })
+      );
+    }
+  }
+
+  if (varDef.multi) {
+    if (parsedValue && !Array.isArray(parsedValue)) {
+      errors.push(
+        i18n.translate('xpack.ingestManager.datasourceValidation.invalidArrayErrorMessage', {
+          defaultMessage: 'Invalid format',
+        })
+      );
+    }
+    if (
+      varDef.required &&
+      (!parsedValue || (Array.isArray(parsedValue) && parsedValue.length === 0))
+    ) {
+      errors.push(
+        i18n.translate('xpack.ingestManager.datasourceValidation.requiredErrorMessage', {
+          defaultMessage: '{fieldName} is required',
+          values: {
+            fieldName: varDef.title || varDef.name,
+          },
+        })
+      );
+    }
+  }
+
+  return errors.length ? errors : null;
+};
+
+export const validationHasErrors = (
+  validationResults:
+    | DatasourceValidationResults
+    | DatasourceInputValidationResults
+    | DatasourceConfigValidationResults
+) => {
+  const flattenedValidation = getFlattenedObject(validationResults);
+  return !!Object.entries(flattenedValidation).find(([, value]) => !!value);
+};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx
index b45beef4a8b5e..105d6c66a5704 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx
@@ -9,17 +9,16 @@ import { FormattedMessage } from '@kbn/i18n/react';
 import {
   EuiSteps,
   EuiPanel,
-  EuiFlexGrid,
   EuiFlexGroup,
   EuiFlexItem,
   EuiFormRow,
-  EuiFieldText,
   EuiButtonEmpty,
   EuiSpacer,
   EuiEmptyPrompt,
   EuiText,
   EuiButton,
   EuiComboBox,
+  EuiCallOut,
 } from '@elastic/eui';
 import {
   AgentConfig,
@@ -28,21 +27,37 @@ import {
   NewDatasource,
   DatasourceInput,
 } from '../../../types';
+import { Loading } from '../../../components';
 import { packageToConfigDatasourceInputs } from '../../../services';
-import { DatasourceInputPanel } from './components';
+import { DatasourceValidationResults, validationHasErrors } from './services';
+import { DatasourceInputPanel, DatasourceInputVarField } from './components';
 
 export const StepConfigureDatasource: React.FunctionComponent<{
   agentConfig: AgentConfig;
   packageInfo: PackageInfo;
   datasource: NewDatasource;
   updateDatasource: (fields: Partial<NewDatasource>) => void;
+  validationResults: DatasourceValidationResults;
   backLink: JSX.Element;
   cancelUrl: string;
   onNext: () => void;
-}> = ({ agentConfig, packageInfo, datasource, updateDatasource, backLink, cancelUrl, onNext }) => {
+}> = ({
+  agentConfig,
+  packageInfo,
+  datasource,
+  updateDatasource,
+  validationResults,
+  backLink,
+  cancelUrl,
+  onNext,
+}) => {
   // Form show/hide states
   const [isShowingAdvancedDefine, setIsShowingAdvancedDefine] = useState<boolean>(false);
 
+  // Form submit state
+  const [submitAttempted, setSubmitAttempted] = useState<boolean>(false);
+  const hasErrors = validationResults ? validationHasErrors(validationResults) : false;
+
   // Update datasource's package and config info
   useEffect(() => {
     const dsPackage = datasource.package;
@@ -81,56 +96,56 @@ export const StepConfigureDatasource: React.FunctionComponent<{
   }, [datasource.package, datasource.config_id, agentConfig, packageInfo, updateDatasource]);
 
   // Step A, define datasource
-  const DefineDatasource = (
+  const renderDefineDatasource = () => (
     <EuiPanel>
-      <EuiFlexGrid columns={2}>
-        <EuiFlexItem>
-          <EuiFormRow
-            label={
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.stepConfigure.datasourceNameInputLabel"
-                defaultMessage="Data source name"
-              />
-            }
-          >
-            <EuiFieldText
-              value={datasource.name}
-              onChange={e =>
-                updateDatasource({
-                  name: e.target.value,
-                })
-              }
-            />
-          </EuiFormRow>
+      <EuiFlexGroup>
+        <EuiFlexItem grow={1}>
+          <DatasourceInputVarField
+            varDef={{
+              name: 'name',
+              title: i18n.translate(
+                'xpack.ingestManager.createDatasource.stepConfigure.datasourceNameInputLabel',
+                {
+                  defaultMessage: 'Data source name',
+                }
+              ),
+              type: 'text',
+              required: true,
+            }}
+            value={datasource.name}
+            onChange={(newValue: any) => {
+              updateDatasource({
+                name: newValue,
+              });
+            }}
+            errors={validationResults!.name}
+            forceShowErrors={submitAttempted}
+          />
         </EuiFlexItem>
-        <EuiFlexItem>
-          <EuiFormRow
-            label={
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.stepConfigure.datasourceDescriptionInputLabel"
-                defaultMessage="Description"
-              />
-            }
-            labelAppend={
-              <EuiText size="xs" color="subdued">
-                <FormattedMessage
-                  id="xpack.ingestManager.createDatasource.stepConfigure.inputVarFieldOptionalLabel"
-                  defaultMessage="Optional"
-                />
-              </EuiText>
-            }
-          >
-            <EuiFieldText
-              value={datasource.description}
-              onChange={e =>
-                updateDatasource({
-                  description: e.target.value,
-                })
-              }
-            />
-          </EuiFormRow>
+        <EuiFlexItem grow={1}>
+          <DatasourceInputVarField
+            varDef={{
+              name: 'description',
+              title: i18n.translate(
+                'xpack.ingestManager.createDatasource.stepConfigure.datasourceDescriptionInputLabel',
+                {
+                  defaultMessage: 'Description',
+                }
+              ),
+              type: 'text',
+              required: false,
+            }}
+            value={datasource.description}
+            onChange={(newValue: any) => {
+              updateDatasource({
+                description: newValue,
+              });
+            }}
+            errors={validationResults!.description}
+            forceShowErrors={submitAttempted}
+          />
         </EuiFlexItem>
-      </EuiFlexGrid>
+      </EuiFlexGroup>
       <EuiSpacer size="m" />
       <EuiButtonEmpty
         flush="left"
@@ -147,8 +162,8 @@ export const StepConfigureDatasource: React.FunctionComponent<{
       {isShowingAdvancedDefine ? (
         <Fragment>
           <EuiSpacer size="m" />
-          <EuiFlexGrid columns={2}>
-            <EuiFlexItem>
+          <EuiFlexGroup>
+            <EuiFlexItem grow={1}>
               <EuiFormRow
                 label={
                   <FormattedMessage
@@ -174,7 +189,8 @@ export const StepConfigureDatasource: React.FunctionComponent<{
                 />
               </EuiFormRow>
             </EuiFlexItem>
-          </EuiFlexGrid>
+            <EuiFlexItem grow={1} />
+          </EuiFlexGroup>
         </Fragment>
       ) : null}
     </EuiPanel>
@@ -182,7 +198,7 @@ export const StepConfigureDatasource: React.FunctionComponent<{
 
   // Step B, configure inputs (and their streams)
   // Assume packages only export one datasource for now
-  const ConfigureInputs =
+  const renderConfigureInputs = () =>
     packageInfo.datasources &&
     packageInfo.datasources[0] &&
     packageInfo.datasources[0].inputs &&
@@ -208,6 +224,8 @@ export const StepConfigureDatasource: React.FunctionComponent<{
                     inputs: newInputs,
                   });
                 }}
+                inputValidationResults={validationResults!.inputs![datasourceInput.type]}
+                forceShowErrors={submitAttempted}
               />
             </EuiFlexItem>
           ) : null;
@@ -232,7 +250,7 @@ export const StepConfigureDatasource: React.FunctionComponent<{
       </EuiPanel>
     );
 
-  return (
+  return validationResults ? (
     <EuiFlexGroup direction="column" gutterSize="none">
       <EuiFlexItem>
         <EuiFlexGroup direction="column" gutterSize="none">
@@ -251,7 +269,7 @@ export const StepConfigureDatasource: React.FunctionComponent<{
                       defaultMessage: 'Define your datasource',
                     }
                   ),
-                  children: DefineDatasource,
+                  children: renderDefineDatasource(),
                 },
                 {
                   title: i18n.translate(
@@ -260,13 +278,34 @@ export const StepConfigureDatasource: React.FunctionComponent<{
                       defaultMessage: 'Choose the data you want to collect',
                     }
                   ),
-                  children: ConfigureInputs,
+                  children: renderConfigureInputs(),
                 },
               ]}
             />
           </EuiFlexItem>
         </EuiFlexGroup>
       </EuiFlexItem>
+      {hasErrors && submitAttempted ? (
+        <EuiFlexItem>
+          <EuiCallOut
+            title={i18n.translate(
+              'xpack.ingestManager.createDatasource.stepConfigure.validationErrorTitle',
+              {
+                defaultMessage: 'Your data source configuration has errors',
+              }
+            )}
+            color="danger"
+          >
+            <p>
+              <FormattedMessage
+                id="xpack.ingestManager.createDatasource.stepConfigure.validationErrorText"
+                defaultMessage="Please fix the above errors before continuing"
+              />
+            </p>
+          </EuiCallOut>
+          <EuiSpacer size="m" />
+        </EuiFlexItem>
+      ) : null}
       <EuiFlexItem>
         <EuiFlexGroup justifyContent="flexEnd">
           <EuiFlexItem grow={false}>
@@ -278,7 +317,17 @@ export const StepConfigureDatasource: React.FunctionComponent<{
             </EuiButtonEmpty>
           </EuiFlexItem>
           <EuiFlexItem grow={false}>
-            <EuiButton fill iconType="arrowRight" iconSide="right" onClick={() => onNext()}>
+            <EuiButton
+              fill
+              iconType="arrowRight"
+              iconSide="right"
+              onClick={() => {
+                setSubmitAttempted(true);
+                if (!hasErrors) {
+                  onNext();
+                }
+              }}
+            >
               <FormattedMessage
                 id="xpack.ingestManager.createDatasource.continueButtonText"
                 defaultMessage="Continue"
@@ -288,5 +337,7 @@ export const StepConfigureDatasource: React.FunctionComponent<{
         </EuiFlexGroup>
       </EuiFlexItem>
     </EuiFlexGroup>
+  ) : (
+    <Loading />
   );
 };
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts
index 0aa08602e4d4d..5ebd1300baf65 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts
@@ -4,6 +4,8 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+export { getFlattenedObject } from '../../../../../../../src/core/utils';
+
 export {
   agentConfigRouteService,
   datasourceRouteService,
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts
index 333a9b049fa85..32615278b67d7 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts
@@ -16,6 +16,7 @@ export {
   NewDatasource,
   DatasourceInput,
   DatasourceInputStream,
+  DatasourceConfigRecordEntry,
   // API schemas - Agent Config
   GetAgentConfigsResponse,
   GetAgentConfigsResponseItem,
@@ -56,6 +57,7 @@ export {
   RegistryVarsEntry,
   RegistryInput,
   RegistryStream,
+  RegistryDatasource,
   PackageList,
   PackageListItem,
   PackagesGroupedByStatus,
@@ -70,4 +72,5 @@ export {
   DeletePackageResponse,
   DetailViewPanelName,
   InstallStatus,
+  InstallationStatus,
 } from '../../../../common';

From 578e443bdd79ea6436289ee39703816fe7419ebd Mon Sep 17 00:00:00 2001
From: Dmitry Lemeshko <dzmitry.lemechko@elastic.co>
Date: Thu, 9 Apr 2020 00:08:21 +0300
Subject: [PATCH 04/78] FTR: add chromium-based Edge browser support (#61684)

* bump dependency, add edge support in ftr services

* add config files

* fix browser version for msedge

* use npm ms-chromium-edge-driver

* download edge driver aside from session creation

* move dependency to dev

* update dist/index file

* bump edge-driver version

* change type to msedge to match w3c spec

* fix discover tests for Edge

* Revert "fix discover tests for Edge"

This reverts commit 87e7fdd256433ef1ad392147d6bd63b925552b37.

* bump driver version up

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 package.json                                  |    5 +-
 packages/kbn-pm/dist/index.js                 | 1105 +++--------------
 .../lib/config/schema.ts                      |    2 +-
 test/functional/config.edge.js                |   34 +
 test/functional/services/browser.ts           |    4 +-
 .../web_element_wrapper.ts                    |    9 +-
 test/functional/services/remote/browsers.ts   |    1 +
 test/functional/services/remote/remote.ts     |   17 +-
 test/functional/services/remote/webdriver.ts  |   50 +-
 x-pack/test/functional/config.edge.js         |   21 +
 yarn.lock                                     |  320 ++++-
 11 files changed, 556 insertions(+), 1012 deletions(-)
 create mode 100644 test/functional/config.edge.js
 create mode 100644 x-pack/test/functional/config.edge.js

diff --git a/package.json b/package.json
index 4c5db5321c282..bd0fec3a5c116 100644
--- a/package.json
+++ b/package.json
@@ -376,7 +376,7 @@
     "@types/recompose": "^0.30.6",
     "@types/redux-actions": "^2.6.1",
     "@types/request": "^2.48.2",
-    "@types/selenium-webdriver": "^4.0.5",
+    "@types/selenium-webdriver": "4.0.9",
     "@types/semver": "^5.5.0",
     "@types/sinon": "^7.0.13",
     "@types/strip-ansi": "^3.0.0",
@@ -462,6 +462,7 @@
     "load-grunt-config": "^3.0.1",
     "mocha": "^7.1.1",
     "mock-http-server": "1.3.0",
+    "ms-chromium-edge-driver": "^0.2.0",
     "multistream": "^2.1.1",
     "murmurhash3js": "3.0.1",
     "mutation-observer": "^1.0.3",
@@ -480,7 +481,7 @@
     "react-textarea-autosize": "^7.1.2",
     "regenerate": "^1.4.0",
     "sass-lint": "^1.12.1",
-    "selenium-webdriver": "^4.0.0-alpha.5",
+    "selenium-webdriver": "^4.0.0-alpha.7",
     "simple-git": "1.116.0",
     "simplebar-react": "^2.1.0",
     "sinon": "^7.4.2",
diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js
index 0cc1ad6326671..7a858deff41d3 100644
--- a/packages/kbn-pm/dist/index.js
+++ b/packages/kbn-pm/dist/index.js
@@ -79260,7 +79260,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; });
 
-/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(928);
+/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(923);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; });
 
 /*
@@ -79445,9 +79445,9 @@ const pAll = __webpack_require__(707);
 const arrify = __webpack_require__(709);
 const globby = __webpack_require__(710);
 const isGlob = __webpack_require__(604);
-const cpFile = __webpack_require__(913);
-const junk = __webpack_require__(925);
-const CpyError = __webpack_require__(926);
+const cpFile = __webpack_require__(908);
+const junk = __webpack_require__(920);
+const CpyError = __webpack_require__(921);
 
 const defaultOptions = {
 	ignoreJunk: true
@@ -79697,8 +79697,8 @@ const fs = __webpack_require__(23);
 const arrayUnion = __webpack_require__(711);
 const glob = __webpack_require__(713);
 const fastGlob = __webpack_require__(718);
-const dirGlob = __webpack_require__(906);
-const gitignore = __webpack_require__(909);
+const dirGlob = __webpack_require__(901);
+const gitignore = __webpack_require__(904);
 
 const DEFAULT_FILTER = () => false;
 
@@ -81531,11 +81531,11 @@ module.exports.generateTasks = pkg.generateTasks;
 Object.defineProperty(exports, "__esModule", { value: true });
 var optionsManager = __webpack_require__(720);
 var taskManager = __webpack_require__(721);
-var reader_async_1 = __webpack_require__(877);
-var reader_stream_1 = __webpack_require__(901);
-var reader_sync_1 = __webpack_require__(902);
-var arrayUtils = __webpack_require__(904);
-var streamUtils = __webpack_require__(905);
+var reader_async_1 = __webpack_require__(872);
+var reader_stream_1 = __webpack_require__(896);
+var reader_sync_1 = __webpack_require__(897);
+var arrayUtils = __webpack_require__(899);
+var streamUtils = __webpack_require__(900);
 /**
  * Synchronous API.
  */
@@ -82175,9 +82175,9 @@ var extend = __webpack_require__(838);
  */
 
 var compilers = __webpack_require__(841);
-var parsers = __webpack_require__(873);
-var cache = __webpack_require__(874);
-var utils = __webpack_require__(875);
+var parsers = __webpack_require__(868);
+var cache = __webpack_require__(869);
+var utils = __webpack_require__(870);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -100710,9 +100710,9 @@ var toRegex = __webpack_require__(729);
  */
 
 var compilers = __webpack_require__(858);
-var parsers = __webpack_require__(869);
-var Extglob = __webpack_require__(872);
-var utils = __webpack_require__(871);
+var parsers = __webpack_require__(864);
+var Extglob = __webpack_require__(867);
+var utils = __webpack_require__(866);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -101222,7 +101222,7 @@ var parsers = __webpack_require__(862);
  * Module dependencies
  */
 
-var debug = __webpack_require__(864)('expand-brackets');
+var debug = __webpack_require__(801)('expand-brackets');
 var extend = __webpack_require__(738);
 var Snapdragon = __webpack_require__(768);
 var toRegex = __webpack_require__(729);
@@ -101816,839 +101816,12 @@ exports.createRegex = function(pattern, include) {
 /* 864 */
 /***/ (function(module, exports, __webpack_require__) {
 
-/**
- * Detect Electron renderer process, which is node, but we should
- * treat as a browser.
- */
-
-if (typeof process !== 'undefined' && process.type === 'renderer') {
-  module.exports = __webpack_require__(865);
-} else {
-  module.exports = __webpack_require__(868);
-}
-
-
-/***/ }),
-/* 865 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/**
- * This is the web browser implementation of `debug()`.
- *
- * Expose `debug()` as the module.
- */
-
-exports = module.exports = __webpack_require__(866);
-exports.log = log;
-exports.formatArgs = formatArgs;
-exports.save = save;
-exports.load = load;
-exports.useColors = useColors;
-exports.storage = 'undefined' != typeof chrome
-               && 'undefined' != typeof chrome.storage
-                  ? chrome.storage.local
-                  : localstorage();
-
-/**
- * Colors.
- */
-
-exports.colors = [
-  'lightseagreen',
-  'forestgreen',
-  'goldenrod',
-  'dodgerblue',
-  'darkorchid',
-  'crimson'
-];
-
-/**
- * Currently only WebKit-based Web Inspectors, Firefox >= v31,
- * and the Firebug extension (any Firefox version) are known
- * to support "%c" CSS customizations.
- *
- * TODO: add a `localStorage` variable to explicitly enable/disable colors
- */
-
-function useColors() {
-  // NB: In an Electron preload script, document will be defined but not fully
-  // initialized. Since we know we're in Chrome, we'll just detect this case
-  // explicitly
-  if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
-    return true;
-  }
-
-  // is webkit? http://stackoverflow.com/a/16459606/376773
-  // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
-  return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
-    // is firebug? http://stackoverflow.com/a/398120/376773
-    (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
-    // is firefox >= v31?
-    // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
-    (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
-    // double check webkit in userAgent just in case we are in a worker
-    (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
-}
-
-/**
- * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
- */
-
-exports.formatters.j = function(v) {
-  try {
-    return JSON.stringify(v);
-  } catch (err) {
-    return '[UnexpectedJSONParseError]: ' + err.message;
-  }
-};
-
-
-/**
- * Colorize log arguments if enabled.
- *
- * @api public
- */
-
-function formatArgs(args) {
-  var useColors = this.useColors;
-
-  args[0] = (useColors ? '%c' : '')
-    + this.namespace
-    + (useColors ? ' %c' : ' ')
-    + args[0]
-    + (useColors ? '%c ' : ' ')
-    + '+' + exports.humanize(this.diff);
-
-  if (!useColors) return;
-
-  var c = 'color: ' + this.color;
-  args.splice(1, 0, c, 'color: inherit')
-
-  // the final "%c" is somewhat tricky, because there could be other
-  // arguments passed either before or after the %c, so we need to
-  // figure out the correct index to insert the CSS into
-  var index = 0;
-  var lastC = 0;
-  args[0].replace(/%[a-zA-Z%]/g, function(match) {
-    if ('%%' === match) return;
-    index++;
-    if ('%c' === match) {
-      // we only are interested in the *last* %c
-      // (the user may have provided their own)
-      lastC = index;
-    }
-  });
-
-  args.splice(lastC, 0, c);
-}
-
-/**
- * Invokes `console.log()` when available.
- * No-op when `console.log` is not a "function".
- *
- * @api public
- */
-
-function log() {
-  // this hackery is required for IE8/9, where
-  // the `console.log` function doesn't have 'apply'
-  return 'object' === typeof console
-    && console.log
-    && Function.prototype.apply.call(console.log, console, arguments);
-}
-
-/**
- * Save `namespaces`.
- *
- * @param {String} namespaces
- * @api private
- */
-
-function save(namespaces) {
-  try {
-    if (null == namespaces) {
-      exports.storage.removeItem('debug');
-    } else {
-      exports.storage.debug = namespaces;
-    }
-  } catch(e) {}
-}
-
-/**
- * Load `namespaces`.
- *
- * @return {String} returns the previously persisted debug modes
- * @api private
- */
-
-function load() {
-  var r;
-  try {
-    r = exports.storage.debug;
-  } catch(e) {}
-
-  // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
-  if (!r && typeof process !== 'undefined' && 'env' in process) {
-    r = process.env.DEBUG;
-  }
-
-  return r;
-}
-
-/**
- * Enable namespaces listed in `localStorage.debug` initially.
- */
-
-exports.enable(load());
-
-/**
- * Localstorage attempts to return the localstorage.
- *
- * This is necessary because safari throws
- * when a user disables cookies/localstorage
- * and you attempt to access it.
- *
- * @return {LocalStorage}
- * @api private
- */
-
-function localstorage() {
-  try {
-    return window.localStorage;
-  } catch (e) {}
-}
-
-
-/***/ }),
-/* 866 */
-/***/ (function(module, exports, __webpack_require__) {
-
-
-/**
- * This is the common logic for both the Node.js and web browser
- * implementations of `debug()`.
- *
- * Expose `debug()` as the module.
- */
-
-exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
-exports.coerce = coerce;
-exports.disable = disable;
-exports.enable = enable;
-exports.enabled = enabled;
-exports.humanize = __webpack_require__(867);
-
-/**
- * The currently active debug mode names, and names to skip.
- */
-
-exports.names = [];
-exports.skips = [];
-
-/**
- * Map of special "%n" handling functions, for the debug "format" argument.
- *
- * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
- */
-
-exports.formatters = {};
-
-/**
- * Previous log timestamp.
- */
-
-var prevTime;
-
-/**
- * Select a color.
- * @param {String} namespace
- * @return {Number}
- * @api private
- */
-
-function selectColor(namespace) {
-  var hash = 0, i;
-
-  for (i in namespace) {
-    hash  = ((hash << 5) - hash) + namespace.charCodeAt(i);
-    hash |= 0; // Convert to 32bit integer
-  }
-
-  return exports.colors[Math.abs(hash) % exports.colors.length];
-}
-
-/**
- * Create a debugger with the given `namespace`.
- *
- * @param {String} namespace
- * @return {Function}
- * @api public
- */
-
-function createDebug(namespace) {
-
-  function debug() {
-    // disabled?
-    if (!debug.enabled) return;
-
-    var self = debug;
-
-    // set `diff` timestamp
-    var curr = +new Date();
-    var ms = curr - (prevTime || curr);
-    self.diff = ms;
-    self.prev = prevTime;
-    self.curr = curr;
-    prevTime = curr;
-
-    // turn the `arguments` into a proper Array
-    var args = new Array(arguments.length);
-    for (var i = 0; i < args.length; i++) {
-      args[i] = arguments[i];
-    }
-
-    args[0] = exports.coerce(args[0]);
-
-    if ('string' !== typeof args[0]) {
-      // anything else let's inspect with %O
-      args.unshift('%O');
-    }
-
-    // apply any `formatters` transformations
-    var index = 0;
-    args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
-      // if we encounter an escaped % then don't increase the array index
-      if (match === '%%') return match;
-      index++;
-      var formatter = exports.formatters[format];
-      if ('function' === typeof formatter) {
-        var val = args[index];
-        match = formatter.call(self, val);
-
-        // now we need to remove `args[index]` since it's inlined in the `format`
-        args.splice(index, 1);
-        index--;
-      }
-      return match;
-    });
-
-    // apply env-specific formatting (colors, etc.)
-    exports.formatArgs.call(self, args);
-
-    var logFn = debug.log || exports.log || console.log.bind(console);
-    logFn.apply(self, args);
-  }
-
-  debug.namespace = namespace;
-  debug.enabled = exports.enabled(namespace);
-  debug.useColors = exports.useColors();
-  debug.color = selectColor(namespace);
-
-  // env-specific initialization logic for debug instances
-  if ('function' === typeof exports.init) {
-    exports.init(debug);
-  }
-
-  return debug;
-}
-
-/**
- * Enables a debug mode by namespaces. This can include modes
- * separated by a colon and wildcards.
- *
- * @param {String} namespaces
- * @api public
- */
-
-function enable(namespaces) {
-  exports.save(namespaces);
-
-  exports.names = [];
-  exports.skips = [];
-
-  var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
-  var len = split.length;
-
-  for (var i = 0; i < len; i++) {
-    if (!split[i]) continue; // ignore empty strings
-    namespaces = split[i].replace(/\*/g, '.*?');
-    if (namespaces[0] === '-') {
-      exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
-    } else {
-      exports.names.push(new RegExp('^' + namespaces + '$'));
-    }
-  }
-}
-
-/**
- * Disable debug output.
- *
- * @api public
- */
-
-function disable() {
-  exports.enable('');
-}
-
-/**
- * Returns true if the given mode name is enabled, false otherwise.
- *
- * @param {String} name
- * @return {Boolean}
- * @api public
- */
-
-function enabled(name) {
-  var i, len;
-  for (i = 0, len = exports.skips.length; i < len; i++) {
-    if (exports.skips[i].test(name)) {
-      return false;
-    }
-  }
-  for (i = 0, len = exports.names.length; i < len; i++) {
-    if (exports.names[i].test(name)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-/**
- * Coerce `val`.
- *
- * @param {Mixed} val
- * @return {Mixed}
- * @api private
- */
-
-function coerce(val) {
-  if (val instanceof Error) return val.stack || val.message;
-  return val;
-}
-
-
-/***/ }),
-/* 867 */
-/***/ (function(module, exports) {
-
-/**
- * Helpers.
- */
-
-var s = 1000;
-var m = s * 60;
-var h = m * 60;
-var d = h * 24;
-var y = d * 365.25;
-
-/**
- * Parse or format the given `val`.
- *
- * Options:
- *
- *  - `long` verbose formatting [false]
- *
- * @param {String|Number} val
- * @param {Object} [options]
- * @throws {Error} throw an error if val is not a non-empty string or a number
- * @return {String|Number}
- * @api public
- */
-
-module.exports = function(val, options) {
-  options = options || {};
-  var type = typeof val;
-  if (type === 'string' && val.length > 0) {
-    return parse(val);
-  } else if (type === 'number' && isNaN(val) === false) {
-    return options.long ? fmtLong(val) : fmtShort(val);
-  }
-  throw new Error(
-    'val is not a non-empty string or a valid number. val=' +
-      JSON.stringify(val)
-  );
-};
-
-/**
- * Parse the given `str` and return milliseconds.
- *
- * @param {String} str
- * @return {Number}
- * @api private
- */
-
-function parse(str) {
-  str = String(str);
-  if (str.length > 100) {
-    return;
-  }
-  var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
-    str
-  );
-  if (!match) {
-    return;
-  }
-  var n = parseFloat(match[1]);
-  var type = (match[2] || 'ms').toLowerCase();
-  switch (type) {
-    case 'years':
-    case 'year':
-    case 'yrs':
-    case 'yr':
-    case 'y':
-      return n * y;
-    case 'days':
-    case 'day':
-    case 'd':
-      return n * d;
-    case 'hours':
-    case 'hour':
-    case 'hrs':
-    case 'hr':
-    case 'h':
-      return n * h;
-    case 'minutes':
-    case 'minute':
-    case 'mins':
-    case 'min':
-    case 'm':
-      return n * m;
-    case 'seconds':
-    case 'second':
-    case 'secs':
-    case 'sec':
-    case 's':
-      return n * s;
-    case 'milliseconds':
-    case 'millisecond':
-    case 'msecs':
-    case 'msec':
-    case 'ms':
-      return n;
-    default:
-      return undefined;
-  }
-}
-
-/**
- * Short format for `ms`.
- *
- * @param {Number} ms
- * @return {String}
- * @api private
- */
-
-function fmtShort(ms) {
-  if (ms >= d) {
-    return Math.round(ms / d) + 'd';
-  }
-  if (ms >= h) {
-    return Math.round(ms / h) + 'h';
-  }
-  if (ms >= m) {
-    return Math.round(ms / m) + 'm';
-  }
-  if (ms >= s) {
-    return Math.round(ms / s) + 's';
-  }
-  return ms + 'ms';
-}
-
-/**
- * Long format for `ms`.
- *
- * @param {Number} ms
- * @return {String}
- * @api private
- */
-
-function fmtLong(ms) {
-  return plural(ms, d, 'day') ||
-    plural(ms, h, 'hour') ||
-    plural(ms, m, 'minute') ||
-    plural(ms, s, 'second') ||
-    ms + ' ms';
-}
-
-/**
- * Pluralization helper.
- */
-
-function plural(ms, n, name) {
-  if (ms < n) {
-    return;
-  }
-  if (ms < n * 1.5) {
-    return Math.floor(ms / n) + ' ' + name;
-  }
-  return Math.ceil(ms / n) + ' ' + name + 's';
-}
-
-
-/***/ }),
-/* 868 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/**
- * Module dependencies.
- */
-
-var tty = __webpack_require__(478);
-var util = __webpack_require__(29);
-
-/**
- * This is the Node.js implementation of `debug()`.
- *
- * Expose `debug()` as the module.
- */
-
-exports = module.exports = __webpack_require__(866);
-exports.init = init;
-exports.log = log;
-exports.formatArgs = formatArgs;
-exports.save = save;
-exports.load = load;
-exports.useColors = useColors;
-
-/**
- * Colors.
- */
-
-exports.colors = [6, 2, 3, 4, 5, 1];
-
-/**
- * Build up the default `inspectOpts` object from the environment variables.
- *
- *   $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
- */
-
-exports.inspectOpts = Object.keys(process.env).filter(function (key) {
-  return /^debug_/i.test(key);
-}).reduce(function (obj, key) {
-  // camel-case
-  var prop = key
-    .substring(6)
-    .toLowerCase()
-    .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() });
-
-  // coerce string value into JS value
-  var val = process.env[key];
-  if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
-  else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
-  else if (val === 'null') val = null;
-  else val = Number(val);
-
-  obj[prop] = val;
-  return obj;
-}, {});
-
-/**
- * The file descriptor to write the `debug()` calls to.
- * Set the `DEBUG_FD` env variable to override with another value. i.e.:
- *
- *   $ DEBUG_FD=3 node script.js 3>debug.log
- */
-
-var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
-
-if (1 !== fd && 2 !== fd) {
-  util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')()
-}
-
-var stream = 1 === fd ? process.stdout :
-             2 === fd ? process.stderr :
-             createWritableStdioStream(fd);
-
-/**
- * Is stdout a TTY? Colored output is enabled when `true`.
- */
-
-function useColors() {
-  return 'colors' in exports.inspectOpts
-    ? Boolean(exports.inspectOpts.colors)
-    : tty.isatty(fd);
-}
-
-/**
- * Map %o to `util.inspect()`, all on a single line.
- */
-
-exports.formatters.o = function(v) {
-  this.inspectOpts.colors = this.useColors;
-  return util.inspect(v, this.inspectOpts)
-    .split('\n').map(function(str) {
-      return str.trim()
-    }).join(' ');
-};
-
-/**
- * Map %o to `util.inspect()`, allowing multiple lines if needed.
- */
-
-exports.formatters.O = function(v) {
-  this.inspectOpts.colors = this.useColors;
-  return util.inspect(v, this.inspectOpts);
-};
-
-/**
- * Adds ANSI color escape codes if enabled.
- *
- * @api public
- */
-
-function formatArgs(args) {
-  var name = this.namespace;
-  var useColors = this.useColors;
-
-  if (useColors) {
-    var c = this.color;
-    var prefix = '  \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m';
-
-    args[0] = prefix + args[0].split('\n').join('\n' + prefix);
-    args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
-  } else {
-    args[0] = new Date().toUTCString()
-      + ' ' + name + ' ' + args[0];
-  }
-}
-
-/**
- * Invokes `util.format()` with the specified arguments and writes to `stream`.
- */
-
-function log() {
-  return stream.write(util.format.apply(util, arguments) + '\n');
-}
-
-/**
- * Save `namespaces`.
- *
- * @param {String} namespaces
- * @api private
- */
-
-function save(namespaces) {
-  if (null == namespaces) {
-    // If you set a process.env field to null or undefined, it gets cast to the
-    // string 'null' or 'undefined'. Just delete instead.
-    delete process.env.DEBUG;
-  } else {
-    process.env.DEBUG = namespaces;
-  }
-}
-
-/**
- * Load `namespaces`.
- *
- * @return {String} returns the previously persisted debug modes
- * @api private
- */
-
-function load() {
-  return process.env.DEBUG;
-}
-
-/**
- * Copied from `node/src/node.js`.
- *
- * XXX: It's lame that node doesn't expose this API out-of-the-box. It also
- * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
- */
-
-function createWritableStdioStream (fd) {
-  var stream;
-  var tty_wrap = process.binding('tty_wrap');
-
-  // Note stream._type is used for test-module-load-list.js
-
-  switch (tty_wrap.guessHandleType(fd)) {
-    case 'TTY':
-      stream = new tty.WriteStream(fd);
-      stream._type = 'tty';
-
-      // Hack to have stream not keep the event loop alive.
-      // See https://github.com/joyent/node/issues/1726
-      if (stream._handle && stream._handle.unref) {
-        stream._handle.unref();
-      }
-      break;
-
-    case 'FILE':
-      var fs = __webpack_require__(23);
-      stream = new fs.SyncWriteStream(fd, { autoClose: false });
-      stream._type = 'fs';
-      break;
-
-    case 'PIPE':
-    case 'TCP':
-      var net = __webpack_require__(806);
-      stream = new net.Socket({
-        fd: fd,
-        readable: false,
-        writable: true
-      });
-
-      // FIXME Should probably have an option in net.Socket to create a
-      // stream from an existing fd which is writable only. But for now
-      // we'll just add this hack and set the `readable` member to false.
-      // Test: ./node test/fixtures/echo.js < /etc/passwd
-      stream.readable = false;
-      stream.read = null;
-      stream._type = 'pipe';
-
-      // FIXME Hack to have stream not keep the event loop alive.
-      // See https://github.com/joyent/node/issues/1726
-      if (stream._handle && stream._handle.unref) {
-        stream._handle.unref();
-      }
-      break;
-
-    default:
-      // Probably an error on in uv_guess_handle()
-      throw new Error('Implement me. Unknown stream file type!');
-  }
-
-  // For supporting legacy API we put the FD here.
-  stream.fd = fd;
-
-  stream._isStdio = true;
-
-  return stream;
-}
-
-/**
- * Init logic for `debug` instances.
- *
- * Create a new `inspectOpts` object in case `useColors` is set
- * differently for a particular `debug` instance.
- */
-
-function init (debug) {
-  debug.inspectOpts = {};
-
-  var keys = Object.keys(exports.inspectOpts);
-  for (var i = 0; i < keys.length; i++) {
-    debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
-  }
-}
-
-/**
- * Enable namespaces listed in `process.env.DEBUG` initially.
- */
-
-exports.enable(load());
-
-
-/***/ }),
-/* 869 */
-/***/ (function(module, exports, __webpack_require__) {
-
 "use strict";
 
 
 var brackets = __webpack_require__(859);
-var define = __webpack_require__(870);
-var utils = __webpack_require__(871);
+var define = __webpack_require__(865);
+var utils = __webpack_require__(866);
 
 /**
  * Characters to use in text regex (we want to "not" match
@@ -102803,7 +101976,7 @@ module.exports = parsers;
 
 
 /***/ }),
-/* 870 */
+/* 865 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102841,7 +102014,7 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 /***/ }),
-/* 871 */
+/* 866 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102917,7 +102090,7 @@ utils.createRegex = function(str) {
 
 
 /***/ }),
-/* 872 */
+/* 867 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102928,7 +102101,7 @@ utils.createRegex = function(str) {
  */
 
 var Snapdragon = __webpack_require__(768);
-var define = __webpack_require__(870);
+var define = __webpack_require__(865);
 var extend = __webpack_require__(738);
 
 /**
@@ -102936,7 +102109,7 @@ var extend = __webpack_require__(738);
  */
 
 var compilers = __webpack_require__(858);
-var parsers = __webpack_require__(869);
+var parsers = __webpack_require__(864);
 
 /**
  * Customize Snapdragon parser and renderer
@@ -103002,7 +102175,7 @@ module.exports = Extglob;
 
 
 /***/ }),
-/* 873 */
+/* 868 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103092,14 +102265,14 @@ function textRegex(pattern) {
 
 
 /***/ }),
-/* 874 */
+/* 869 */
 /***/ (function(module, exports, __webpack_require__) {
 
 module.exports = new (__webpack_require__(850))();
 
 
 /***/ }),
-/* 875 */
+/* 870 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103117,7 +102290,7 @@ utils.define = __webpack_require__(837);
 utils.diff = __webpack_require__(854);
 utils.extend = __webpack_require__(838);
 utils.pick = __webpack_require__(855);
-utils.typeOf = __webpack_require__(876);
+utils.typeOf = __webpack_require__(871);
 utils.unique = __webpack_require__(741);
 
 /**
@@ -103415,7 +102588,7 @@ utils.unixify = function(options) {
 
 
 /***/ }),
-/* 876 */
+/* 871 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -103550,7 +102723,7 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 877 */
+/* 872 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103569,9 +102742,9 @@ var __extends = (this && this.__extends) || (function () {
     };
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
-var readdir = __webpack_require__(878);
-var reader_1 = __webpack_require__(891);
-var fs_stream_1 = __webpack_require__(895);
+var readdir = __webpack_require__(873);
+var reader_1 = __webpack_require__(886);
+var fs_stream_1 = __webpack_require__(890);
 var ReaderAsync = /** @class */ (function (_super) {
     __extends(ReaderAsync, _super);
     function ReaderAsync() {
@@ -103632,15 +102805,15 @@ exports.default = ReaderAsync;
 
 
 /***/ }),
-/* 878 */
+/* 873 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const readdirSync = __webpack_require__(879);
-const readdirAsync = __webpack_require__(887);
-const readdirStream = __webpack_require__(890);
+const readdirSync = __webpack_require__(874);
+const readdirAsync = __webpack_require__(882);
+const readdirStream = __webpack_require__(885);
 
 module.exports = exports = readdirAsyncPath;
 exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath;
@@ -103724,7 +102897,7 @@ function readdirStreamStat (dir, options) {
 
 
 /***/ }),
-/* 879 */
+/* 874 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103732,11 +102905,11 @@ function readdirStreamStat (dir, options) {
 
 module.exports = readdirSync;
 
-const DirectoryReader = __webpack_require__(880);
+const DirectoryReader = __webpack_require__(875);
 
 let syncFacade = {
-  fs: __webpack_require__(885),
-  forEach: __webpack_require__(886),
+  fs: __webpack_require__(880),
+  forEach: __webpack_require__(881),
   sync: true
 };
 
@@ -103765,7 +102938,7 @@ function readdirSync (dir, options, internalOptions) {
 
 
 /***/ }),
-/* 880 */
+/* 875 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103774,9 +102947,9 @@ function readdirSync (dir, options, internalOptions) {
 const Readable = __webpack_require__(27).Readable;
 const EventEmitter = __webpack_require__(379).EventEmitter;
 const path = __webpack_require__(16);
-const normalizeOptions = __webpack_require__(881);
-const stat = __webpack_require__(883);
-const call = __webpack_require__(884);
+const normalizeOptions = __webpack_require__(876);
+const stat = __webpack_require__(878);
+const call = __webpack_require__(879);
 
 /**
  * Asynchronously reads the contents of a directory and streams the results
@@ -104152,14 +103325,14 @@ module.exports = DirectoryReader;
 
 
 /***/ }),
-/* 881 */
+/* 876 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const path = __webpack_require__(16);
-const globToRegExp = __webpack_require__(882);
+const globToRegExp = __webpack_require__(877);
 
 module.exports = normalizeOptions;
 
@@ -104336,7 +103509,7 @@ function normalizeOptions (options, internalOptions) {
 
 
 /***/ }),
-/* 882 */
+/* 877 */
 /***/ (function(module, exports) {
 
 module.exports = function (glob, opts) {
@@ -104473,13 +103646,13 @@ module.exports = function (glob, opts) {
 
 
 /***/ }),
-/* 883 */
+/* 878 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const call = __webpack_require__(884);
+const call = __webpack_require__(879);
 
 module.exports = stat;
 
@@ -104554,7 +103727,7 @@ function symlinkStat (fs, path, lstats, callback) {
 
 
 /***/ }),
-/* 884 */
+/* 879 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104615,14 +103788,14 @@ function callOnce (fn) {
 
 
 /***/ }),
-/* 885 */
+/* 880 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const fs = __webpack_require__(23);
-const call = __webpack_require__(884);
+const call = __webpack_require__(879);
 
 /**
  * A facade around {@link fs.readdirSync} that allows it to be called
@@ -104686,7 +103859,7 @@ exports.lstat = function (path, callback) {
 
 
 /***/ }),
-/* 886 */
+/* 881 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104715,7 +103888,7 @@ function syncForEach (array, iterator, done) {
 
 
 /***/ }),
-/* 887 */
+/* 882 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104723,12 +103896,12 @@ function syncForEach (array, iterator, done) {
 
 module.exports = readdirAsync;
 
-const maybe = __webpack_require__(888);
-const DirectoryReader = __webpack_require__(880);
+const maybe = __webpack_require__(883);
+const DirectoryReader = __webpack_require__(875);
 
 let asyncFacade = {
   fs: __webpack_require__(23),
-  forEach: __webpack_require__(889),
+  forEach: __webpack_require__(884),
   async: true
 };
 
@@ -104770,7 +103943,7 @@ function readdirAsync (dir, options, callback, internalOptions) {
 
 
 /***/ }),
-/* 888 */
+/* 883 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104797,7 +103970,7 @@ module.exports = function maybe (cb, promise) {
 
 
 /***/ }),
-/* 889 */
+/* 884 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104833,7 +104006,7 @@ function asyncForEach (array, iterator, done) {
 
 
 /***/ }),
-/* 890 */
+/* 885 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104841,11 +104014,11 @@ function asyncForEach (array, iterator, done) {
 
 module.exports = readdirStream;
 
-const DirectoryReader = __webpack_require__(880);
+const DirectoryReader = __webpack_require__(875);
 
 let streamFacade = {
   fs: __webpack_require__(23),
-  forEach: __webpack_require__(889),
+  forEach: __webpack_require__(884),
   async: true
 };
 
@@ -104865,16 +104038,16 @@ function readdirStream (dir, options, internalOptions) {
 
 
 /***/ }),
-/* 891 */
+/* 886 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 var path = __webpack_require__(16);
-var deep_1 = __webpack_require__(892);
-var entry_1 = __webpack_require__(894);
-var pathUtil = __webpack_require__(893);
+var deep_1 = __webpack_require__(887);
+var entry_1 = __webpack_require__(889);
+var pathUtil = __webpack_require__(888);
 var Reader = /** @class */ (function () {
     function Reader(options) {
         this.options = options;
@@ -104940,13 +104113,13 @@ exports.default = Reader;
 
 
 /***/ }),
-/* 892 */
+/* 887 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var pathUtils = __webpack_require__(893);
+var pathUtils = __webpack_require__(888);
 var patternUtils = __webpack_require__(722);
 var DeepFilter = /** @class */ (function () {
     function DeepFilter(options, micromatchOptions) {
@@ -105030,7 +104203,7 @@ exports.default = DeepFilter;
 
 
 /***/ }),
-/* 893 */
+/* 888 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105061,13 +104234,13 @@ exports.makeAbsolute = makeAbsolute;
 
 
 /***/ }),
-/* 894 */
+/* 889 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var pathUtils = __webpack_require__(893);
+var pathUtils = __webpack_require__(888);
 var patternUtils = __webpack_require__(722);
 var EntryFilter = /** @class */ (function () {
     function EntryFilter(options, micromatchOptions) {
@@ -105153,7 +104326,7 @@ exports.default = EntryFilter;
 
 
 /***/ }),
-/* 895 */
+/* 890 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105173,8 +104346,8 @@ var __extends = (this && this.__extends) || (function () {
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
 var stream = __webpack_require__(27);
-var fsStat = __webpack_require__(896);
-var fs_1 = __webpack_require__(900);
+var fsStat = __webpack_require__(891);
+var fs_1 = __webpack_require__(895);
 var FileSystemStream = /** @class */ (function (_super) {
     __extends(FileSystemStream, _super);
     function FileSystemStream() {
@@ -105224,14 +104397,14 @@ exports.default = FileSystemStream;
 
 
 /***/ }),
-/* 896 */
+/* 891 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const optionsManager = __webpack_require__(897);
-const statProvider = __webpack_require__(899);
+const optionsManager = __webpack_require__(892);
+const statProvider = __webpack_require__(894);
 /**
  * Asynchronous API.
  */
@@ -105262,13 +104435,13 @@ exports.statSync = statSync;
 
 
 /***/ }),
-/* 897 */
+/* 892 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fsAdapter = __webpack_require__(898);
+const fsAdapter = __webpack_require__(893);
 function prepare(opts) {
     const options = Object.assign({
         fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined),
@@ -105281,7 +104454,7 @@ exports.prepare = prepare;
 
 
 /***/ }),
-/* 898 */
+/* 893 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105304,7 +104477,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter;
 
 
 /***/ }),
-/* 899 */
+/* 894 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105356,7 +104529,7 @@ exports.isFollowedSymlink = isFollowedSymlink;
 
 
 /***/ }),
-/* 900 */
+/* 895 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105387,7 +104560,7 @@ exports.default = FileSystem;
 
 
 /***/ }),
-/* 901 */
+/* 896 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105407,9 +104580,9 @@ var __extends = (this && this.__extends) || (function () {
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
 var stream = __webpack_require__(27);
-var readdir = __webpack_require__(878);
-var reader_1 = __webpack_require__(891);
-var fs_stream_1 = __webpack_require__(895);
+var readdir = __webpack_require__(873);
+var reader_1 = __webpack_require__(886);
+var fs_stream_1 = __webpack_require__(890);
 var TransformStream = /** @class */ (function (_super) {
     __extends(TransformStream, _super);
     function TransformStream(reader) {
@@ -105477,7 +104650,7 @@ exports.default = ReaderStream;
 
 
 /***/ }),
-/* 902 */
+/* 897 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105496,9 +104669,9 @@ var __extends = (this && this.__extends) || (function () {
     };
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
-var readdir = __webpack_require__(878);
-var reader_1 = __webpack_require__(891);
-var fs_sync_1 = __webpack_require__(903);
+var readdir = __webpack_require__(873);
+var reader_1 = __webpack_require__(886);
+var fs_sync_1 = __webpack_require__(898);
 var ReaderSync = /** @class */ (function (_super) {
     __extends(ReaderSync, _super);
     function ReaderSync() {
@@ -105558,7 +104731,7 @@ exports.default = ReaderSync;
 
 
 /***/ }),
-/* 903 */
+/* 898 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105577,8 +104750,8 @@ var __extends = (this && this.__extends) || (function () {
     };
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
-var fsStat = __webpack_require__(896);
-var fs_1 = __webpack_require__(900);
+var fsStat = __webpack_require__(891);
+var fs_1 = __webpack_require__(895);
 var FileSystemSync = /** @class */ (function (_super) {
     __extends(FileSystemSync, _super);
     function FileSystemSync() {
@@ -105624,7 +104797,7 @@ exports.default = FileSystemSync;
 
 
 /***/ }),
-/* 904 */
+/* 899 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105640,7 +104813,7 @@ exports.flatten = flatten;
 
 
 /***/ }),
-/* 905 */
+/* 900 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105661,13 +104834,13 @@ exports.merge = merge;
 
 
 /***/ }),
-/* 906 */
+/* 901 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const path = __webpack_require__(16);
-const pathType = __webpack_require__(907);
+const pathType = __webpack_require__(902);
 
 const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
 
@@ -105733,13 +104906,13 @@ module.exports.sync = (input, opts) => {
 
 
 /***/ }),
-/* 907 */
+/* 902 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const fs = __webpack_require__(23);
-const pify = __webpack_require__(908);
+const pify = __webpack_require__(903);
 
 function type(fn, fn2, fp) {
 	if (typeof fp !== 'string') {
@@ -105782,7 +104955,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink');
 
 
 /***/ }),
-/* 908 */
+/* 903 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105873,7 +105046,7 @@ module.exports = (obj, opts) => {
 
 
 /***/ }),
-/* 909 */
+/* 904 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105881,9 +105054,9 @@ module.exports = (obj, opts) => {
 const fs = __webpack_require__(23);
 const path = __webpack_require__(16);
 const fastGlob = __webpack_require__(718);
-const gitIgnore = __webpack_require__(910);
-const pify = __webpack_require__(911);
-const slash = __webpack_require__(912);
+const gitIgnore = __webpack_require__(905);
+const pify = __webpack_require__(906);
+const slash = __webpack_require__(907);
 
 const DEFAULT_IGNORE = [
 	'**/node_modules/**',
@@ -105981,7 +105154,7 @@ module.exports.sync = options => {
 
 
 /***/ }),
-/* 910 */
+/* 905 */
 /***/ (function(module, exports) {
 
 // A simple implementation of make-array
@@ -106450,7 +105623,7 @@ module.exports = options => new IgnoreBase(options)
 
 
 /***/ }),
-/* 911 */
+/* 906 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -106525,7 +105698,7 @@ module.exports = (input, options) => {
 
 
 /***/ }),
-/* 912 */
+/* 907 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -106543,17 +105716,17 @@ module.exports = input => {
 
 
 /***/ }),
-/* 913 */
+/* 908 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const path = __webpack_require__(16);
 const {constants: fsConstants} = __webpack_require__(23);
-const pEvent = __webpack_require__(914);
-const CpFileError = __webpack_require__(917);
-const fs = __webpack_require__(921);
-const ProgressEmitter = __webpack_require__(924);
+const pEvent = __webpack_require__(909);
+const CpFileError = __webpack_require__(912);
+const fs = __webpack_require__(916);
+const ProgressEmitter = __webpack_require__(919);
 
 const cpFileAsync = async (source, destination, options, progressEmitter) => {
 	let readError;
@@ -106667,12 +105840,12 @@ module.exports.sync = (source, destination, options) => {
 
 
 /***/ }),
-/* 914 */
+/* 909 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const pTimeout = __webpack_require__(915);
+const pTimeout = __webpack_require__(910);
 
 const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator';
 
@@ -106963,12 +106136,12 @@ module.exports.iterator = (emitter, event, options) => {
 
 
 /***/ }),
-/* 915 */
+/* 910 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const pFinally = __webpack_require__(916);
+const pFinally = __webpack_require__(911);
 
 class TimeoutError extends Error {
 	constructor(message) {
@@ -107014,7 +106187,7 @@ module.exports.TimeoutError = TimeoutError;
 
 
 /***/ }),
-/* 916 */
+/* 911 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -107036,12 +106209,12 @@ module.exports = (promise, onFinally) => {
 
 
 /***/ }),
-/* 917 */
+/* 912 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const NestedError = __webpack_require__(918);
+const NestedError = __webpack_require__(913);
 
 class CpFileError extends NestedError {
 	constructor(message, nested) {
@@ -107055,10 +106228,10 @@ module.exports = CpFileError;
 
 
 /***/ }),
-/* 918 */
+/* 913 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var inherits = __webpack_require__(919);
+var inherits = __webpack_require__(914);
 
 var NestedError = function (message, nested) {
     this.nested = nested;
@@ -107109,7 +106282,7 @@ module.exports = NestedError;
 
 
 /***/ }),
-/* 919 */
+/* 914 */
 /***/ (function(module, exports, __webpack_require__) {
 
 try {
@@ -107117,12 +106290,12 @@ try {
   if (typeof util.inherits !== 'function') throw '';
   module.exports = util.inherits;
 } catch (e) {
-  module.exports = __webpack_require__(920);
+  module.exports = __webpack_require__(915);
 }
 
 
 /***/ }),
-/* 920 */
+/* 915 */
 /***/ (function(module, exports) {
 
 if (typeof Object.create === 'function') {
@@ -107151,16 +106324,16 @@ if (typeof Object.create === 'function') {
 
 
 /***/ }),
-/* 921 */
+/* 916 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const {promisify} = __webpack_require__(29);
 const fs = __webpack_require__(22);
-const makeDir = __webpack_require__(922);
-const pEvent = __webpack_require__(914);
-const CpFileError = __webpack_require__(917);
+const makeDir = __webpack_require__(917);
+const pEvent = __webpack_require__(909);
+const CpFileError = __webpack_require__(912);
 
 const stat = promisify(fs.stat);
 const lstat = promisify(fs.lstat);
@@ -107257,7 +106430,7 @@ exports.copyFileSync = (source, destination, flags) => {
 
 
 /***/ }),
-/* 922 */
+/* 917 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -107265,7 +106438,7 @@ exports.copyFileSync = (source, destination, flags) => {
 const fs = __webpack_require__(23);
 const path = __webpack_require__(16);
 const {promisify} = __webpack_require__(29);
-const semver = __webpack_require__(923);
+const semver = __webpack_require__(918);
 
 const defaults = {
 	mode: 0o777 & (~process.umask()),
@@ -107414,7 +106587,7 @@ module.exports.sync = (input, options) => {
 
 
 /***/ }),
-/* 923 */
+/* 918 */
 /***/ (function(module, exports) {
 
 exports = module.exports = SemVer
@@ -109016,7 +108189,7 @@ function coerce (version, options) {
 
 
 /***/ }),
-/* 924 */
+/* 919 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -109057,7 +108230,7 @@ module.exports = ProgressEmitter;
 
 
 /***/ }),
-/* 925 */
+/* 920 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -109103,12 +108276,12 @@ exports.default = module.exports;
 
 
 /***/ }),
-/* 926 */
+/* 921 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const NestedError = __webpack_require__(927);
+const NestedError = __webpack_require__(922);
 
 class CpyError extends NestedError {
 	constructor(message, nested) {
@@ -109122,7 +108295,7 @@ module.exports = CpyError;
 
 
 /***/ }),
-/* 927 */
+/* 922 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var inherits = __webpack_require__(29).inherits;
@@ -109178,7 +108351,7 @@ module.exports = NestedError;
 
 
 /***/ }),
-/* 928 */
+/* 923 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
index 66f17ab579ec3..f4b91d154cbb8 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
@@ -136,7 +136,7 @@ export const schema = Joi.object()
     browser: Joi.object()
       .keys({
         type: Joi.string()
-          .valid('chrome', 'firefox', 'ie')
+          .valid('chrome', 'firefox', 'ie', 'msedge')
           .default('chrome'),
 
         logPollingMs: Joi.number().default(100),
diff --git a/test/functional/config.edge.js b/test/functional/config.edge.js
new file mode 100644
index 0000000000000..ed68b41e8c89a
--- /dev/null
+++ b/test/functional/config.edge.js
@@ -0,0 +1,34 @@
+/*
+ * 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 default async function({ readConfigFile }) {
+  const defaultConfig = await readConfigFile(require.resolve('./config'));
+
+  return {
+    ...defaultConfig.getAll(),
+
+    browser: {
+      type: 'msedge',
+    },
+
+    junit: {
+      reportName: 'MS Chromium Edge UI Functional Tests',
+    },
+  };
+}
diff --git a/test/functional/services/browser.ts b/test/functional/services/browser.ts
index 5017947e95d03..13d2365c07191 100644
--- a/test/functional/services/browser.ts
+++ b/test/functional/services/browser.ts
@@ -47,7 +47,9 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
      */
     public readonly browserType: string = browserType;
 
-    public readonly isChrome: boolean = browserType === Browsers.Chrome;
+    public readonly isChromium: boolean = [Browsers.Chrome, Browsers.ChromiumEdge].includes(
+      browserType
+    );
 
     public readonly isFirefox: boolean = browserType === Browsers.Firefox;
 
diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts
index 157918df874c8..8b57ecd3c8235 100644
--- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts
+++ b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts
@@ -55,6 +55,7 @@ export class WebElementWrapper {
   private driver: WebDriver = this.webDriver.driver;
   private Keys = Key;
   public isW3CEnabled: boolean = (this.webDriver.driver as any).executor_.w3c === true;
+  public isChromium: boolean = [Browsers.Chrome, Browsers.ChromiumEdge].includes(this.browserType);
 
   public static create(
     webElement: WebElement | WebElementWrapper,
@@ -63,7 +64,7 @@ export class WebElementWrapper {
     timeout: number,
     fixedHeaderHeight: number,
     logger: ToolingLog,
-    browserType: string
+    browserType: Browsers
   ): WebElementWrapper {
     if (webElement instanceof WebElementWrapper) {
       return webElement;
@@ -87,7 +88,7 @@ export class WebElementWrapper {
     private timeout: number,
     private fixedHeaderHeight: number,
     private logger: ToolingLog,
-    private browserType: string
+    private browserType: Browsers
   ) {}
 
   private async _findWithCustomTimeout(
@@ -243,7 +244,7 @@ export class WebElementWrapper {
       return this.clearValueWithKeyboard();
     }
     await this.retryCall(async function clearValue(wrapper) {
-      if (wrapper.browserType === Browsers.Chrome || options.withJS) {
+      if (wrapper.isChromium || options.withJS) {
         // https://bugs.chromium.org/p/chromedriver/issues/detail?id=2702
         await wrapper.driver.executeScript(`arguments[0].value=''`, wrapper._webElement);
       } else {
@@ -275,7 +276,7 @@ export class WebElementWrapper {
         await delay(100);
       }
     } else {
-      if (this.browserType === Browsers.Chrome) {
+      if (this.isChromium) {
         // https://bugs.chromium.org/p/chromedriver/issues/detail?id=30
         await this.retryCall(async function clearValueWithKeyboard(wrapper) {
           await wrapper.driver.executeScript(`arguments[0].select();`, wrapper._webElement);
diff --git a/test/functional/services/remote/browsers.ts b/test/functional/services/remote/browsers.ts
index 46d81f1737a55..aa6e364d0a09d 100644
--- a/test/functional/services/remote/browsers.ts
+++ b/test/functional/services/remote/browsers.ts
@@ -21,4 +21,5 @@ export enum Browsers {
   Chrome = 'chrome',
   Firefox = 'firefox',
   InternetExplorer = 'ie',
+  ChromiumEdge = 'msedge',
 }
diff --git a/test/functional/services/remote/remote.ts b/test/functional/services/remote/remote.ts
index e571a1a7e5551..b0724488cb5db 100644
--- a/test/functional/services/remote/remote.ts
+++ b/test/functional/services/remote/remote.ts
@@ -64,18 +64,23 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
     lifecycle,
     config.get('browser.logPollingMs')
   );
+
   const isW3CEnabled = (driver as any).executor_.w3c;
 
   const caps = await driver.getCapabilities();
-  const browserVersion = caps.get(isW3CEnabled ? 'browserVersion' : 'version');
+  const browserVersion = caps.get(
+    isW3CEnabled || browserType === Browsers.ChromiumEdge ? 'browserVersion' : 'version'
+  );
 
-  log.info(`Remote initialized: ${caps.get('browserName')} ${browserVersion}`);
+  log.info(
+    `Remote initialized: ${caps.get(
+      'browserName'
+    )} ${browserVersion}, w3c compliance=${isW3CEnabled}, collectingCoverage=${collectCoverage}`
+  );
 
-  if (browserType === Browsers.Chrome) {
+  if ([Browsers.Chrome, Browsers.ChromiumEdge].includes(browserType)) {
     log.info(
-      `Chromedriver version: ${
-        caps.get('chrome').chromedriverVersion
-      }, w3c=${isW3CEnabled}, codeCoverage=${collectCoverage}`
+      `${browserType}driver version: ${caps.get(browserType)[`${browserType}driverVersion`]}`
     );
   }
 
diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts
index 3bf5b865aa7ba..fc0b5bbb787c8 100644
--- a/test/functional/services/remote/webdriver.ts
+++ b/test/functional/services/remote/webdriver.ts
@@ -31,10 +31,12 @@ import { Builder, Capabilities, By, logging, until } from 'selenium-webdriver';
 import chrome from 'selenium-webdriver/chrome';
 import firefox from 'selenium-webdriver/firefox';
 // @ts-ignore internal modules are not typed
+import edge from 'selenium-webdriver/edge';
+import { installDriver } from 'ms-chromium-edge-driver';
+// @ts-ignore internal modules are not typed
 import { Executor } from 'selenium-webdriver/lib/http';
 // @ts-ignore internal modules are not typed
 import { getLogger } from 'selenium-webdriver/lib/logging';
-
 import { pollForLogEntry$ } from './poll_for_log_entry';
 import { createStdoutSocket } from './create_stdout_stream';
 import { preventParallelCalls } from './prevent_parallel_calls';
@@ -63,6 +65,7 @@ Executor.prototype.execute = preventParallelCalls(
 );
 
 let attemptCounter = 0;
+let edgePaths: { driverPath: string | undefined; browserPath: string | undefined };
 async function attemptToCreateCommand(
   log: ToolingLog,
   browserType: Browsers,
@@ -74,6 +77,46 @@ async function attemptToCreateCommand(
 
   const buildDriverInstance = async () => {
     switch (browserType) {
+      case 'msedge': {
+        if (edgePaths && edgePaths.browserPath && edgePaths.driverPath) {
+          const edgeOptions = new edge.Options();
+          if (headlessBrowser === '1') {
+            // @ts-ignore internal modules are not typed
+            edgeOptions.headless();
+          }
+          // @ts-ignore internal modules are not typed
+          edgeOptions.setEdgeChromium(true);
+          // @ts-ignore internal modules are not typed
+          edgeOptions.setBinaryPath(edgePaths.browserPath);
+          const session = await new Builder()
+            .forBrowser('MicrosoftEdge')
+            .setEdgeOptions(edgeOptions)
+            .setEdgeService(new edge.ServiceBuilder(edgePaths.driverPath))
+            .build();
+          return {
+            session,
+            consoleLog$: pollForLogEntry$(
+              session,
+              logging.Type.BROWSER,
+              logPollingMs,
+              lifecycle.cleanup.after$
+            ).pipe(
+              takeUntil(lifecycle.cleanup.after$),
+              map(({ message, level: { name: level } }) => ({
+                message: message.replace(/\\n/g, '\n'),
+                level,
+              }))
+            ),
+          };
+        } else {
+          throw new Error(
+            `Chromium Edge session requires browser or driver path to be defined: ${JSON.stringify(
+              edgePaths
+            )}`
+          );
+        }
+      }
+
       case 'chrome': {
         const chromeCapabilities = Capabilities.chrome();
         const chromeOptions = [
@@ -265,6 +308,11 @@ export async function initWebDriver(
     log.verbose(entry.message);
   });
 
+  // download Edge driver only in case of usage
+  if (browserType === Browsers.ChromiumEdge) {
+    edgePaths = await installDriver();
+  }
+
   return await Promise.race([
     (async () => {
       await delay(2 * MINUTE);
diff --git a/x-pack/test/functional/config.edge.js b/x-pack/test/functional/config.edge.js
new file mode 100644
index 0000000000000..882fb6fea3686
--- /dev/null
+++ b/x-pack/test/functional/config.edge.js
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export default async function({ readConfigFile }) {
+  const chromeConfig = await readConfigFile(require.resolve('./config'));
+
+  return {
+    ...chromeConfig.getAll(),
+
+    browser: {
+      type: 'msedge',
+    },
+
+    junit: {
+      reportName: 'MS Chromium Edge XPack UI Functional Tests',
+    },
+  };
+}
diff --git a/yarn.lock b/yarn.lock
index 77ab69c715573..3f04b2d26a013 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2499,6 +2499,11 @@
   resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
   integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==
 
+"@sindresorhus/is@^2.0.0":
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.0.tgz#6ad4ca610f696098e92954ab431ff83bea0ce13f"
+  integrity sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==
+
 "@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0":
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.6.0.tgz#ec7670432ae9c8eb710400d112c201a362d83393"
@@ -3398,6 +3403,13 @@
     "@svgr/plugin-svgo" "^4.2.0"
     loader-utils "^1.2.3"
 
+"@szmarczak/http-timer@^4.0.0":
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152"
+  integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==
+  dependencies:
+    defer-to-connect "^2.0.0"
+
 "@testim/chrome-version@^1.0.7":
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.0.7.tgz#0cd915785ec4190f08a3a6acc9b61fc38fb5f1a9"
@@ -3646,6 +3658,16 @@
   resolved "https://registry.yarnpkg.com/@types/browserslist-useragent/-/browserslist-useragent-3.0.0.tgz#d425c9818182ce71ce53866798cee9c7d41d6e53"
   integrity sha512-ZBvKzg3yyWNYEkwxAzdmUzp27sFvw+1m080/+2lwrt+eltNefn1f4fnpMyrjOla31p8zLleCYqQXw+3EETfn0w==
 
+"@types/cacheable-request@^6.0.1":
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
+  integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
+  dependencies:
+    "@types/http-cache-semantics" "*"
+    "@types/keyv" "*"
+    "@types/node" "*"
+    "@types/responselike" "*"
+
 "@types/caseless@*":
   version "0.12.2"
   resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
@@ -4015,6 +4037,11 @@
     "@types/react" "*"
     hoist-non-react-statics "^3.3.0"
 
+"@types/http-cache-semantics@*":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
+  integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
+
 "@types/indent-string@^3.0.0":
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/@types/indent-string/-/indent-string-3.0.0.tgz#9ebb391ceda548926f5819ad16405349641b999f"
@@ -4146,6 +4173,13 @@
   dependencies:
     "@types/node" "*"
 
+"@types/keyv@*":
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
+  integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
+  dependencies:
+    "@types/node" "*"
+
 "@types/license-checker@15.0.0":
   version "15.0.0"
   resolved "https://registry.yarnpkg.com/@types/license-checker/-/license-checker-15.0.0.tgz#685d69e2cf61ffd862320434601f51c85e28bba1"
@@ -4617,6 +4651,13 @@
     "@types/tough-cookie" "*"
     form-data "^2.5.0"
 
+"@types/responselike@*":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
+  integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
+  dependencies:
+    "@types/node" "*"
+
 "@types/retry@^0.12.0":
   version "0.12.0"
   resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
@@ -4632,10 +4673,10 @@
   resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.28.tgz#9ce8fa048c1e8c85cb71d7fe4d704e000226036f"
   integrity sha512-SMA+fUwULwK7sd/ZJicUztiPs8F1yCPwF3O23Z9uQ32ME5Ha0NmDK9+QTsYE4O2tHXChzXomSWWeIhCnoN1LqA==
 
-"@types/selenium-webdriver@^4.0.5":
-  version "4.0.5"
-  resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.5.tgz#23041a4948c82daf2df9836e4d2358fec10d3e24"
-  integrity sha512-ma1aL1znI3ptEbSQgbywgadrRCJouPIACSfOl/bPwu/TPNSyyE/+o9jZ6+bpDVTtIdksZuVKpq4SR1ip3DRduw==
+"@types/selenium-webdriver@4.0.9":
+  version "4.0.9"
+  resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.9.tgz#12621e55b2ef8f6c98bd17fe23fa720c6cba16bd"
+  integrity sha512-HopIwBE7GUXsscmt/J0DhnFXLSmO04AfxT6b8HAprknwka7pqEWquWDMXxCjd+NUHK9MkCe1SDKKsMiNmCItbQ==
 
 "@types/semver@^5.5.0":
   version "5.5.0"
@@ -7358,13 +7399,18 @@ binaryextensions@2:
   resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935"
   integrity sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==
 
-bindings@^1.5.0:
+bindings@1, bindings@^1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
   integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
   dependencies:
     file-uri-to-path "1.0.0"
 
+bindings@~1.2.0:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
+  integrity sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=
+
 bit-twiddle@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/bit-twiddle/-/bit-twiddle-1.0.2.tgz#0c6c1fabe2b23d17173d9a61b7b7093eb9e1769e"
@@ -7898,7 +7944,7 @@ buffer@^5.1.0, buffer@^5.2.0:
     base64-js "^1.0.2"
     ieee754 "^1.1.4"
 
-builtin-modules@^1.0.0:
+builtin-modules@^1.0.0, builtin-modules@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
   integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
@@ -8045,6 +8091,13 @@ cache-loader@^4.1.0:
     neo-async "^2.6.1"
     schema-utils "^2.0.0"
 
+cacheable-lookup@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-2.0.0.tgz#33b1e56f17507f5cf9bb46075112d65473fb7713"
+  integrity sha512-s2piO6LvA7xnL1AR03wuEdSx3BZT3tIJpZ56/lcJwzO/6DTJZlTs7X3lrvPxk6d1PlDe6PrVe2TjlUIZNFglAQ==
+  dependencies:
+    keyv "^4.0.0"
+
 cacheable-request@^2.1.1:
   version "2.1.4"
   resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d"
@@ -8058,6 +8111,19 @@ cacheable-request@^2.1.1:
     normalize-url "2.0.1"
     responselike "1.0.2"
 
+cacheable-request@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58"
+  integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==
+  dependencies:
+    clone-response "^1.0.2"
+    get-stream "^5.1.0"
+    http-cache-semantics "^4.0.0"
+    keyv "^4.0.0"
+    lowercase-keys "^2.0.0"
+    normalize-url "^4.1.0"
+    responselike "^2.0.0"
+
 cachedir@2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8"
@@ -8886,7 +8952,7 @@ clone-regexp@^1.0.0:
     is-regexp "^1.0.0"
     is-supported-regexp-flag "^1.0.0"
 
-clone-response@1.0.2:
+clone-response@1.0.2, clone-response@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
   integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
@@ -9150,16 +9216,16 @@ commander@4.1.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83"
   integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw==
 
+commander@^2.12.1, commander@^2.20.0, commander@^2.7.1:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
 commander@^2.13.0, commander@^2.15.1, commander@^2.16.0, commander@^2.19.0:
   version "2.20.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
   integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
 
-commander@^2.20.0, commander@^2.7.1:
-  version "2.20.3"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
-  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-
 commander@^2.8.1:
   version "2.18.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970"
@@ -10575,7 +10641,7 @@ debug-fabulous@1.X:
     memoizee "0.4.X"
     object-assign "4.X"
 
-debug@2.6.9, debug@^2.0.0, debug@^2.1.0, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9:
+debug@2, debug@2.6.9, debug@^2.0.0, debug@^2.1.0, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
   integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -10647,6 +10713,13 @@ decompress-response@^4.2.0:
   dependencies:
     mimic-response "^2.0.0"
 
+decompress-response@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f"
+  integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==
+  dependencies:
+    mimic-response "^2.0.0"
+
 decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
@@ -10798,6 +10871,11 @@ defaults@^1.0.3:
   dependencies:
     clone "^1.0.2"
 
+defer-to-connect@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1"
+  integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==
+
 define-properties@^1.1.2, define-properties@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -13239,6 +13317,17 @@ fetch-mock@^7.3.9:
     path-to-regexp "^2.2.1"
     whatwg-url "^6.5.0"
 
+ffi@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/ffi/-/ffi-2.3.0.tgz#fa1a7b3d85c0fa8c83d96947a64b5192bc47f858"
+  integrity sha512-vkPA9Hf9CVuQ5HeMZykYvrZF2QNJ/iKGLkyDkisBnoOOFeFXZQhUPxBARPBIZMJVulvBI2R+jgofW03gyPpJcQ==
+  dependencies:
+    bindings "~1.2.0"
+    debug "2"
+    nan "2"
+    ref "1"
+    ref-struct "1"
+
 figgy-pudding@^3.5.1:
   version "3.5.1"
   resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@@ -14716,6 +14805,27 @@ got@5.6.0:
     unzip-response "^1.0.0"
     url-parse-lax "^1.0.0"
 
+got@^10.6.0:
+  version "10.6.0"
+  resolved "https://registry.yarnpkg.com/got/-/got-10.6.0.tgz#ac3876261a4d8e5fc4f81186f79955ce7b0501dc"
+  integrity sha512-3LIdJNTdCFbbJc+h/EH0V5lpNpbJ6Bfwykk21lcQvQsEcrzdi/ltCyQehFHLzJ/ka0UMH4Slg0hkYvAZN9qUDg==
+  dependencies:
+    "@sindresorhus/is" "^2.0.0"
+    "@szmarczak/http-timer" "^4.0.0"
+    "@types/cacheable-request" "^6.0.1"
+    cacheable-lookup "^2.0.0"
+    cacheable-request "^7.0.1"
+    decompress-response "^5.0.0"
+    duplexer3 "^0.1.4"
+    get-stream "^5.0.0"
+    lowercase-keys "^2.0.0"
+    mimic-response "^2.1.0"
+    p-cancelable "^2.0.0"
+    p-event "^4.0.0"
+    responselike "^2.0.0"
+    to-readable-stream "^2.0.0"
+    type-fest "^0.10.0"
+
 got@^3.2.0:
   version "3.3.1"
   resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
@@ -15816,6 +15926,11 @@ http-cache-semantics@3.8.1:
   resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
   integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==
 
+http-cache-semantics@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
+  integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
+
 http-deceiver@^1.2.7:
   version "1.2.7"
   resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
@@ -16854,6 +16969,11 @@ is-generator-fn@^2.0.0:
   resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.0.0.tgz#038c31b774709641bda678b1f06a4e3227c10b3e"
   integrity sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==
 
+is-generator-function@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
+  integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==
+
 is-glob@4.0.0, is-glob@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
@@ -18124,6 +18244,11 @@ json-buffer@3.0.0:
   resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
   integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
 
+json-buffer@3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+  integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
 json-parse-better-errors@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a"
@@ -18359,7 +18484,7 @@ jsx-to-string@^1.4.0:
     json-stringify-pretty-compact "^1.0.1"
     react "^0.14.0"
 
-jszip@^3.1.5:
+jszip@^3.2.2:
   version "3.2.2"
   resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.2.2.tgz#b143816df7e106a9597a94c77493385adca5bd1d"
   integrity sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==
@@ -18535,6 +18660,13 @@ keyv@3.0.0:
   dependencies:
     json-buffer "3.0.0"
 
+keyv@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.0.tgz#2d1dab694926b2d427e4c74804a10850be44c12f"
+  integrity sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==
+  dependencies:
+    json-buffer "3.0.1"
+
 killable@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -19503,6 +19635,11 @@ lowercase-keys@^1.0.0:
   resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
   integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
 
+lowercase-keys@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+  integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+
 lowlight@~1.9.1:
   version "1.9.1"
   resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.9.1.tgz#ed7c3dffc36f8c1f263735c0fe0c907847c11250"
@@ -20163,6 +20300,11 @@ mimic-response@^2.0.0:
   resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
   integrity sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==
 
+mimic-response@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
+  integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
+
 mimos@4.x.x:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/mimos/-/mimos-4.0.0.tgz#76e3d27128431cb6482fd15b20475719ad626a5a"
@@ -20591,6 +20733,19 @@ move-concurrently@^1.0.1:
     rimraf "^2.5.4"
     run-queue "^1.0.3"
 
+ms-chromium-edge-driver@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/ms-chromium-edge-driver/-/ms-chromium-edge-driver-0.2.0.tgz#0e0c6fd9fd1d1d36db97b2b3d7e9d4ba4d2de456"
+  integrity sha512-RkDsBPnMLjRna7q4LlvtLb+CHPei9gZapnlxm3ayWKk3Ab6HmDsz/17xG2eyqkKX5UcKeo04YlLZ345tO7OolA==
+  dependencies:
+    extract-zip "^1.6.7"
+    got "^10.6.0"
+    lodash "4.17.15"
+    tslint "^6.1.0"
+    tslint-config-prettier "^1.18.0"
+    util "^0.12.2"
+    windows-registry "^0.1.5"
+
 ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -20703,7 +20858,7 @@ mute-stream@0.0.8:
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
   integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
 
-nan@^2.12.1, nan@^2.13.2:
+nan@2, nan@^2.12.1, nan@^2.13.2:
   version "2.14.0"
   resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
   integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
@@ -21206,6 +21361,11 @@ normalize-url@^3.3.0:
   resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
   integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
 
+normalize-url@^4.1.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
+  integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
+
 now-and-later@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.0.tgz#bc61cbb456d79cb32207ce47ca05136ff2e7d6ee"
@@ -21891,6 +22051,11 @@ p-cancelable@^0.4.0:
   resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0"
   integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==
 
+p-cancelable@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
+  integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
+
 p-defer@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
@@ -21903,7 +22068,7 @@ p-each-series@^1.0.0:
   dependencies:
     p-reduce "^1.0.0"
 
-p-event@^4.1.0:
+p-event@^4.0.0, p-event@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.1.0.tgz#e92bb866d7e8e5b732293b1c8269d38e9982bf8e"
   integrity sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==
@@ -24952,6 +25117,31 @@ redux@^4.0.5:
     loose-envify "^1.4.0"
     symbol-observable "^1.2.0"
 
+ref-struct@1, ref-struct@^1.0.2:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/ref-struct/-/ref-struct-1.1.0.tgz#5d5ee65ad41cefc3a5c5feb40587261e479edc13"
+  integrity sha1-XV7mWtQc78Olxf60BYcmHkee3BM=
+  dependencies:
+    debug "2"
+    ref "1"
+
+ref-union@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/ref-union/-/ref-union-1.0.1.tgz#3a2397f862f1e75171d687268f43b3f17729f120"
+  integrity sha1-OiOX+GLx51Fx1ocmj0Oz8Xcp8SA=
+  dependencies:
+    debug "2"
+    ref "1"
+
+ref@1, ref@^1.2.0:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/ref/-/ref-1.3.5.tgz#0e33f080cdb94a3d95312b2b3b1fd0f82044ca0f"
+  integrity sha512-2cBCniTtxcGUjDpvFfVpw323a83/0RLSGJJY5l5lcomZWhYpU2cuLdsvYqMixvsdLJ9+sTdzEkju8J8ZHDM2nA==
+  dependencies:
+    bindings "1"
+    debug "2"
+    nan "2"
+
 reflect.ownkeys@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460"
@@ -25691,6 +25881,13 @@ responselike@1.0.2:
   dependencies:
     lowercase-keys "^1.0.0"
 
+responselike@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
+  integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
+  dependencies:
+    lowercase-keys "^2.0.0"
+
 restore-cursor@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@@ -26249,15 +26446,14 @@ select@^1.1.2:
   resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
   integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
 
-selenium-webdriver@^4.0.0-alpha.5:
-  version "4.0.0-alpha.5"
-  resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.5.tgz#e4683b3dbf827d70df09a7e43bf02ebad20fa7c1"
-  integrity sha512-hktl3DSrhzM59yLhWzDGHIX9o56DvA+cVK7Dw6FcJR6qQ4CGzkaHeXQPcdrslkWMTeq0Ci9AmCxq0EMOvm2Rkg==
+selenium-webdriver@^4.0.0-alpha.7:
+  version "4.0.0-alpha.7"
+  resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz#e3879d8457fd7ad8e4424094b7dc0540d99e6797"
+  integrity sha512-D4qnTsyTr91jT8f7MfN+OwY0IlU5+5FmlO5xlgRUV6hDEV8JyYx2NerdTEqDDkNq7RZDYc4VoPALk8l578RBHw==
   dependencies:
-    jszip "^3.1.5"
-    rimraf "^2.6.3"
+    jszip "^3.2.2"
+    rimraf "^2.7.1"
     tmp "0.0.30"
-    xml2js "^0.4.19"
 
 selfsigned@^1.10.7:
   version "1.10.7"
@@ -28648,6 +28844,11 @@ to-object-path@^0.3.0:
   dependencies:
     kind-of "^3.0.2"
 
+to-readable-stream@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8"
+  integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==
+
 to-regex-range@^2.1.0:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
@@ -28927,6 +29128,37 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.2, tslib@^1.9.3:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
   integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
 
+tslint-config-prettier@^1.18.0:
+  version "1.18.0"
+  resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37"
+  integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==
+
+tslint@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.0.tgz#c6c611b8ba0eed1549bf5a59ba05a7732133d851"
+  integrity sha512-fXjYd/61vU6da04E505OZQGb2VCN2Mq3doeWcOIryuG+eqdmFUXTYVwdhnbEu2k46LNLgUYt9bI5icQze/j0bQ==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    builtin-modules "^1.1.1"
+    chalk "^2.3.0"
+    commander "^2.12.1"
+    diff "^4.0.1"
+    glob "^7.1.1"
+    js-yaml "^3.13.1"
+    minimatch "^3.0.4"
+    mkdirp "^0.5.1"
+    resolve "^1.3.2"
+    semver "^5.3.0"
+    tslib "^1.10.0"
+    tsutils "^2.29.0"
+
+tsutils@^2.29.0:
+  version "2.29.0"
+  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
+  integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
+  dependencies:
+    tslib "^1.8.1"
+
 tsutils@^3.17.1:
   version "3.17.1"
   resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
@@ -29431,6 +29663,11 @@ type-detect@^1.0.0:
   resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2"
   integrity sha1-diIXzAbbJY7EiQihKY6LlRIejqI=
 
+type-fest@^0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.10.0.tgz#7f06b2b9fbfc581068d1341ffabd0349ceafc642"
+  integrity sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==
+
 type-fest@^0.3.0, type-fest@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
@@ -30121,6 +30358,16 @@ util@^0.11.0:
   dependencies:
     inherits "2.0.3"
 
+util@^0.12.2:
+  version "0.12.2"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.12.2.tgz#54adb634c9e7c748707af2bf5a8c7ab640cbba2b"
+  integrity sha512-XE+MkWQvglYa+IOfBt5UFG93EmncEMP23UqpgDvVZVFBPxwmkK10QRp6pgU4xICPnWRf/t0zPv4noYSUq9gqUQ==
+  dependencies:
+    inherits "^2.0.3"
+    is-arguments "^1.0.4"
+    is-generator-function "^1.0.7"
+    safe-buffer "^5.1.2"
+
 utila@^0.4.0, utila@~0.4:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
@@ -31277,6 +31524,17 @@ window-size@^0.2.0:
   resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
   integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=
 
+windows-registry@^0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/windows-registry/-/windows-registry-0.1.5.tgz#92c25c960884b0d215e69395f52d8dfaa0ba4ad0"
+  integrity sha512-gMN3ets1fbdP+TApEbbX2TIfBK3MIH5+p9GMvIFS3CNLr7U0Khe5mRj/T5zvwo/pKdhJgDrCLYyaNSs7HYiBCw==
+  dependencies:
+    debug "^2.2.0"
+    ffi "^2.0.0"
+    ref "^1.2.0"
+    ref-struct "^1.0.2"
+    ref-union "^1.0.0"
+
 windows-release@^3.1.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
@@ -31575,14 +31833,6 @@ xml-parse-from-string@^1.0.0:
   resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28"
   integrity sha1-qQKekp09vN7RafPG4oI42VpdWig=
 
-xml2js@^0.4.19, xml2js@^0.4.5:
-  version "0.4.19"
-  resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
-  integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==
-  dependencies:
-    sax ">=0.6.0"
-    xmlbuilder "~9.0.1"
-
 xml2js@^0.4.22:
   version "0.4.22"
   resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.22.tgz#4fa2d846ec803237de86f30aa9b5f70b6600de02"
@@ -31592,6 +31842,14 @@ xml2js@^0.4.22:
     util.promisify "~1.0.0"
     xmlbuilder "~11.0.0"
 
+xml2js@^0.4.5:
+  version "0.4.19"
+  resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
+  integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==
+  dependencies:
+    sax ">=0.6.0"
+    xmlbuilder "~9.0.1"
+
 xml@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"

From e3bd04fcb078a8fd01d315bbde68781bdd8a3cfd Mon Sep 17 00:00:00 2001
From: Gidi Meir Morris <github@gidi.io>
Date: Wed, 8 Apr 2020 22:36:33 +0100
Subject: [PATCH 05/78] [Alerting] Displays warning when a permanent encryption
 key is missing and hides alerting UI appropriately (#62772)

Removes the Security flyout and instead replaces the Alerting List, Connectors List and Alert Flyout with suitable messaging.
Verifies that a permanent Encryption Key has been configured and if it hasn't displays a suitable warning in place, or along side the TLS warning, as needed.
---
 x-pack/plugins/alerting/common/index.ts       |   1 +
 x-pack/plugins/alerting/server/plugin.ts      |   2 +-
 .../alerting/server/routes/health.test.ts     |  58 +++++-
 .../plugins/alerting/server/routes/health.ts  |   8 +-
 .../translations/translations/ja-JP.json      |  17 +-
 .../translations/translations/zh-CN.json      |  17 +-
 .../alert_action_security_call_out.test.tsx   |  78 -------
 .../alert_action_security_call_out.tsx        |  78 -------
 .../application/components/health_check.scss  |  13 ++
 .../components/health_check.test.tsx          | 131 ++++++++++++
 .../application/components/health_check.tsx   | 197 ++++++++++++++++++
 .../prompts/empty_connectors_prompt.scss      |   3 +
 .../prompts/empty_connectors_prompt.tsx       |  55 +++++
 .../components/prompts/empty_prompt.tsx       |  47 +++++
 .../components/security_call_out.test.tsx     |  72 -------
 .../components/security_call_out.tsx          |  75 -------
 .../public/application/home.tsx               |  25 ++-
 .../components/actions_connectors_list.scss   |   4 -
 .../components/actions_connectors_list.tsx    |  53 +----
 .../sections/alert_form/alert_add.test.tsx    |   5 +-
 .../sections/alert_form/alert_add.tsx         | 104 +++++----
 .../sections/alert_form/alert_edit.test.tsx   |   5 +-
 .../sections/alert_form/alert_edit.tsx        | 134 ++++++------
 .../alerts_list/components/alerts_list.tsx    |  42 +---
 24 files changed, 662 insertions(+), 562 deletions(-)
 delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.test.tsx
 delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.tsx
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/health_check.scss
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.scss
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.tsx
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_prompt.tsx
 delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.test.tsx
 delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.tsx

diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts
index 9d4ea69a63609..2574e73dd4f9a 100644
--- a/x-pack/plugins/alerting/common/index.ts
+++ b/x-pack/plugins/alerting/common/index.ts
@@ -17,6 +17,7 @@ export interface ActionGroup {
 
 export interface AlertingFrameworkHealth {
   isSufficientlySecure: boolean;
+  hasPermanentEncryptionKey: boolean;
 }
 
 export const BASE_ALERT_API_PATH = '/api/alert';
diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts
index 172a106226345..fdca6c0a9b503 100644
--- a/x-pack/plugins/alerting/server/plugin.ts
+++ b/x-pack/plugins/alerting/server/plugin.ts
@@ -190,7 +190,7 @@ export class AlertingPlugin {
     unmuteAllAlertRoute(router, this.licenseState);
     muteAlertInstanceRoute(router, this.licenseState);
     unmuteAlertInstanceRoute(router, this.licenseState);
-    healthRoute(router, this.licenseState);
+    healthRoute(router, this.licenseState, plugins.encryptedSavedObjects);
 
     return {
       registerType: alertTypeRegistry.register.bind(alertTypeRegistry),
diff --git a/x-pack/plugins/alerting/server/routes/health.test.ts b/x-pack/plugins/alerting/server/routes/health.test.ts
index 9efe020bc10c4..42c83a7c04deb 100644
--- a/x-pack/plugins/alerting/server/routes/health.test.ts
+++ b/x-pack/plugins/alerting/server/routes/health.test.ts
@@ -10,6 +10,7 @@ import { mockHandlerArguments } from './_mock_handler_arguments';
 import { elasticsearchServiceMock } from '../../../../../src/core/server/mocks';
 import { verifyApiAccess } from '../lib/license_api_access';
 import { mockLicenseState } from '../lib/license_state.mock';
+import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks';
 
 jest.mock('../lib/license_api_access.ts', () => ({
   verifyApiAccess: jest.fn(),
@@ -24,7 +25,9 @@ describe('healthRoute', () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
 
     const [config] = router.get.mock.calls[0];
 
@@ -35,7 +38,9 @@ describe('healthRoute', () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
     const [, handler] = router.get.mock.calls[0];
 
     const elasticsearch = elasticsearchServiceMock.createSetup();
@@ -58,11 +63,37 @@ describe('healthRoute', () => {
     `);
   });
 
+  it('evaluates whether Encrypted Saved Objects is using an ephemeral encryption key', async () => {
+    const router: RouterMock = mockRouter.create();
+
+    const licenseState = mockLicenseState();
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = true;
+    healthRoute(router, licenseState, encryptedSavedObjects);
+    const [, handler] = router.get.mock.calls[0];
+
+    const elasticsearch = elasticsearchServiceMock.createSetup();
+    elasticsearch.adminClient.callAsInternalUser.mockReturnValue(Promise.resolve({}));
+
+    const [context, req, res] = mockHandlerArguments({ elasticsearch }, {}, ['ok']);
+
+    expect(await handler(context, req, res)).toMatchInlineSnapshot(`
+      Object {
+        "body": Object {
+          "hasPermanentEncryptionKey": false,
+          "isSufficientlySecure": true,
+        },
+      }
+    `);
+  });
+
   it('evaluates missing security info from the usage api to mean that the security plugin is disbled', async () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
     const [, handler] = router.get.mock.calls[0];
 
     const elasticsearch = elasticsearchServiceMock.createSetup();
@@ -73,6 +104,7 @@ describe('healthRoute', () => {
     expect(await handler(context, req, res)).toMatchInlineSnapshot(`
       Object {
         "body": Object {
+          "hasPermanentEncryptionKey": true,
           "isSufficientlySecure": true,
         },
       }
@@ -83,7 +115,9 @@ describe('healthRoute', () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
     const [, handler] = router.get.mock.calls[0];
 
     const elasticsearch = elasticsearchServiceMock.createSetup();
@@ -94,6 +128,7 @@ describe('healthRoute', () => {
     expect(await handler(context, req, res)).toMatchInlineSnapshot(`
       Object {
         "body": Object {
+          "hasPermanentEncryptionKey": true,
           "isSufficientlySecure": true,
         },
       }
@@ -104,7 +139,9 @@ describe('healthRoute', () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
     const [, handler] = router.get.mock.calls[0];
 
     const elasticsearch = elasticsearchServiceMock.createSetup();
@@ -117,6 +154,7 @@ describe('healthRoute', () => {
     expect(await handler(context, req, res)).toMatchInlineSnapshot(`
       Object {
         "body": Object {
+          "hasPermanentEncryptionKey": true,
           "isSufficientlySecure": false,
         },
       }
@@ -127,7 +165,9 @@ describe('healthRoute', () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
     const [, handler] = router.get.mock.calls[0];
 
     const elasticsearch = elasticsearchServiceMock.createSetup();
@@ -140,6 +180,7 @@ describe('healthRoute', () => {
     expect(await handler(context, req, res)).toMatchInlineSnapshot(`
       Object {
         "body": Object {
+          "hasPermanentEncryptionKey": true,
           "isSufficientlySecure": false,
         },
       }
@@ -150,7 +191,9 @@ describe('healthRoute', () => {
     const router: RouterMock = mockRouter.create();
 
     const licenseState = mockLicenseState();
-    healthRoute(router, licenseState);
+    const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup();
+    encryptedSavedObjects.usingEphemeralEncryptionKey = false;
+    healthRoute(router, licenseState, encryptedSavedObjects);
     const [, handler] = router.get.mock.calls[0];
 
     const elasticsearch = elasticsearchServiceMock.createSetup();
@@ -163,6 +206,7 @@ describe('healthRoute', () => {
     expect(await handler(context, req, res)).toMatchInlineSnapshot(`
       Object {
         "body": Object {
+          "hasPermanentEncryptionKey": true,
           "isSufficientlySecure": true,
         },
       }
diff --git a/x-pack/plugins/alerting/server/routes/health.ts b/x-pack/plugins/alerting/server/routes/health.ts
index 29c2f3c5730f4..fa2358a1f181c 100644
--- a/x-pack/plugins/alerting/server/routes/health.ts
+++ b/x-pack/plugins/alerting/server/routes/health.ts
@@ -14,6 +14,7 @@ import {
 import { LicenseState } from '../lib/license_state';
 import { verifyApiAccess } from '../lib/license_api_access';
 import { AlertingFrameworkHealth } from '../types';
+import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';
 
 interface XPackUsageSecurity {
   security?: {
@@ -26,7 +27,11 @@ interface XPackUsageSecurity {
   };
 }
 
-export function healthRoute(router: IRouter, licenseState: LicenseState) {
+export function healthRoute(
+  router: IRouter,
+  licenseState: LicenseState,
+  encryptedSavedObjects: EncryptedSavedObjectsPluginSetup
+) {
   router.get(
     {
       path: '/api/alert/_health',
@@ -54,6 +59,7 @@ export function healthRoute(router: IRouter, licenseState: LicenseState) {
 
         const frameworkHealth: AlertingFrameworkHealth = {
           isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled),
+          hasPermanentEncryptionKey: !encryptedSavedObjects.usingEphemeralEncryptionKey,
         };
 
         return res.ok({
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 00ac5b77d00f3..e63e1c8ad2c91 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -15864,8 +15864,6 @@
     "xpack.triggersActionsUI.common.expressionItems.threshold.andLabel": "AND",
     "xpack.triggersActionsUI.common.expressionItems.threshold.descriptionLabel": "タイミング",
     "xpack.triggersActionsUI.common.expressionItems.threshold.popoverTitle": "タイミング",
-    "xpack.triggersActionsUI.components.alertActionSecurityCallOut.enableTlsCta": "TLS を有効にする",
-    "xpack.triggersActionsUI.components.alertActionSecurityCallOut.tlsDisabledTitle": "アラート {action} を実行するには Elasticsearch と Kibana の間に TLS が必要です。",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.actionTypeTitle": "メールに送信",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.addVariablePopoverButton": "変数を追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText": "サーバーからメールを送信します。",
@@ -15960,9 +15958,6 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.viewHeadersSwitch": "HTTP ヘッダーを追加",
     "xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText": "{numErrors, number} {numErrors, plural, one {{singleTitle}} other {{multipleTitle}}}を削除できませんでした",
     "xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText": "{numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} other {{multipleTitle}}}を削除しました",
-    "xpack.triggersActionsUI.components.securityCallOut.enableTlsCta": "TLS を有効にする",
-    "xpack.triggersActionsUI.components.securityCallOut.tlsDisabledDescription": "アラートは API キー に依存し、キーを使用するには Elasticsearch と Kibana の間に TLS が必要です。",
-    "xpack.triggersActionsUI.components.securityCallOut.tlsDisabledTitle": "トランスポートレイヤーセキュリティを有効にする",
     "xpack.triggersActionsUI.connectors.breadcrumbTitle": "コネクター",
     "xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.cancelButtonLabel": "キャンセル",
     "xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.deleteButtonLabel": "{numIdsToDelete, plural, one {{singleTitle}} other {# {multipleTitle}}}を削除 ",
@@ -15986,8 +15981,8 @@
     "xpack.triggersActionsUI.sections.actionConnectorForm.error.requiredNameText": "名前が必要です。",
     "xpack.triggersActionsUI.sections.actionForm.getMoreActionsTitle": "さらにアクションを表示",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.addActionButtonLabel": "コネクターを作成",
-    "xpack.triggersActionsUI.sections.actionsConnectorsList.addActionEmptyBody": "Kibana でトリガーできるメール、Slack, Elasticsearch、およびサードパーティサービスを構成します。",
-    "xpack.triggersActionsUI.sections.actionsConnectorsList.addActionEmptyTitle": "初めてのコネクターを作成する",
+    "xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionEmptyBody": "Kibana でトリガーできるメール、Slack, Elasticsearch、およびサードパーティサービスを構成します。",
+    "xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionEmptyTitle": "初めてのコネクターを作成する",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.buttons.deleteDisabledTitle": "コネクターを削除できません",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.buttons.deleteLabel": "{count} 件を削除",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDescription": "このコネクターを削除",
@@ -16037,7 +16032,6 @@
     "xpack.triggersActionsUI.sections.alertAdd.saveButtonLabel": "保存",
     "xpack.triggersActionsUI.sections.alertAdd.saveErrorNotificationText": "アラートを作成できません。",
     "xpack.triggersActionsUI.sections.alertAdd.saveSuccessNotificationText": "「{alertName}」 を保存しました",
-    "xpack.triggersActionsUI.sections.alertAdd.securityCalloutAction": "作成",
     "xpack.triggersActionsUI.sections.alertAdd.selectIndex": "インデックスを選択してください。",
     "xpack.triggersActionsUI.sections.alertAdd.threshold.closeIndexPopoverLabel": "閉じる",
     "xpack.triggersActionsUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage": "下の表現のエラーを修正してください。",
@@ -16074,7 +16068,6 @@
     "xpack.triggersActionsUI.sections.alertEdit.saveButtonLabel": "保存",
     "xpack.triggersActionsUI.sections.alertEdit.saveErrorNotificationText": "アラートを更新できません。",
     "xpack.triggersActionsUI.sections.alertEdit.saveSuccessNotificationText": "「{alertName}」 を更新しました",
-    "xpack.triggersActionsUI.sections.alertEdit.securityCalloutAction": "編集中",
     "xpack.triggersActionsUI.sections.alertForm.accordion.deleteIconAriaLabel": "削除",
     "xpack.triggersActionsUI.sections.alertForm.actionDisabledTitle": "このアクションは無効です",
     "xpack.triggersActionsUI.sections.alertForm.actionIdLabel": "{connectorInstance} コネクター",
@@ -16126,9 +16119,9 @@
     "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.enableTitle": "有効にする",
     "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.muteTitle": "ミュート",
     "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.popoverButtonTitle": "アクション",
-    "xpack.triggersActionsUI.sections.alertsList.emptyButton": "アラートの作成",
-    "xpack.triggersActionsUI.sections.alertsList.emptyDesc": "トリガーが起きたときにメール、Slack、または別のコネクターを通してアラートを受信します。",
-    "xpack.triggersActionsUI.sections.alertsList.emptyTitle": "初めてのアラートを作成する",
+    "xpack.triggersActionsUI.components.emptyPrompt.emptyButton": "アラートの作成",
+    "xpack.triggersActionsUI.components.emptyPrompt.emptyDesc": "トリガーが起きたときにメール、Slack、または別のコネクターを通してアラートを受信します。",
+    "xpack.triggersActionsUI.components.emptyPrompt.emptyTitle": "初めてのアラートを作成する",
     "xpack.triggersActionsUI.sections.alertsList.multipleTitle": "アラート",
     "xpack.triggersActionsUI.sections.alertsList.searchPlaceholderTitle": "検索",
     "xpack.triggersActionsUI.sections.alertsList.singleTitle": "アラート",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index f6d84431bef7f..cc75ceb988d97 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -15868,8 +15868,6 @@
     "xpack.triggersActionsUI.common.expressionItems.threshold.andLabel": "且",
     "xpack.triggersActionsUI.common.expressionItems.threshold.descriptionLabel": "当",
     "xpack.triggersActionsUI.common.expressionItems.threshold.popoverTitle": "当",
-    "xpack.triggersActionsUI.components.alertActionSecurityCallOut.enableTlsCta": "启用 TLS",
-    "xpack.triggersActionsUI.components.alertActionSecurityCallOut.tlsDisabledTitle": "告警 {action} 在 Elasticsearch 和 Kibana 之间需要 TLS。",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.actionTypeTitle": "发送到电子邮件",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.addVariablePopoverButton": "添加变量",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText": "从您的服务器发送电子邮件。",
@@ -15964,9 +15962,6 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.viewHeadersSwitch": "添加 HTTP 标头",
     "xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText": "无法删除 {numErrors, number} 个{numErrors, plural, one {{singleTitle}} other {{multipleTitle}}}",
     "xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText": "已删除 {numSuccesses, number} 个{numSuccesses, plural, one {{singleTitle}} other {{multipleTitle}}}",
-    "xpack.triggersActionsUI.components.securityCallOut.enableTlsCta": "启用 TLS",
-    "xpack.triggersActionsUI.components.securityCallOut.tlsDisabledDescription": "Alerting 依赖于在 Elasticsearch 和 Kibana 之间需要 TLS 的 API 密钥。",
-    "xpack.triggersActionsUI.components.securityCallOut.tlsDisabledTitle": "启用传输层安全",
     "xpack.triggersActionsUI.connectors.breadcrumbTitle": "连接器",
     "xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.cancelButtonLabel": "取消",
     "xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.deleteButtonLabel": "删除{numIdsToDelete, plural, one {{singleTitle}} other { # 个{multipleTitle}}} ",
@@ -15991,8 +15986,8 @@
     "xpack.triggersActionsUI.sections.actionConnectorForm.error.requiredNameText": "名称必填。",
     "xpack.triggersActionsUI.sections.actionForm.getMoreActionsTitle": "获取更多的操作",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.addActionButtonLabel": "创建连接器",
-    "xpack.triggersActionsUI.sections.actionsConnectorsList.addActionEmptyBody": "配置电子邮件、Slack、Elasticsearch 和 Kibana 可以触发的第三方服务。",
-    "xpack.triggersActionsUI.sections.actionsConnectorsList.addActionEmptyTitle": "创建您的首个连接器",
+    "xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionEmptyBody": "配置电子邮件、Slack、Elasticsearch 和 Kibana 可以触发的第三方服务。",
+    "xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionEmptyTitle": "创建您的首个连接器",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.buttons.deleteDisabledTitle": "无法删除连接器",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.buttons.deleteLabel": "删除 {count} 个",
     "xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDescription": "删除此连接器",
@@ -16042,7 +16037,6 @@
     "xpack.triggersActionsUI.sections.alertAdd.saveButtonLabel": "保存",
     "xpack.triggersActionsUI.sections.alertAdd.saveErrorNotificationText": "无法创建告警。",
     "xpack.triggersActionsUI.sections.alertAdd.saveSuccessNotificationText": "已保存“{alertName}”",
-    "xpack.triggersActionsUI.sections.alertAdd.securityCalloutAction": "创建",
     "xpack.triggersActionsUI.sections.alertAdd.selectIndex": "选择索引。",
     "xpack.triggersActionsUI.sections.alertAdd.threshold.closeIndexPopoverLabel": "关闭",
     "xpack.triggersActionsUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage": "表达式包含错误。",
@@ -16079,7 +16073,6 @@
     "xpack.triggersActionsUI.sections.alertEdit.saveButtonLabel": "保存",
     "xpack.triggersActionsUI.sections.alertEdit.saveErrorNotificationText": "无法更新告警。",
     "xpack.triggersActionsUI.sections.alertEdit.saveSuccessNotificationText": "已更新“{alertName}”",
-    "xpack.triggersActionsUI.sections.alertEdit.securityCalloutAction": "正在编辑",
     "xpack.triggersActionsUI.sections.alertForm.accordion.deleteIconAriaLabel": "删除",
     "xpack.triggersActionsUI.sections.alertForm.actionDisabledTitle": "此操作已禁用",
     "xpack.triggersActionsUI.sections.alertForm.actionIdLabel": "{connectorInstance} 连接器",
@@ -16131,9 +16124,9 @@
     "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.enableTitle": "启用",
     "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.muteTitle": "静音",
     "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.popoverButtonTitle": "操作",
-    "xpack.triggersActionsUI.sections.alertsList.emptyButton": "创建告警",
-    "xpack.triggersActionsUI.sections.alertsList.emptyDesc": "触发条件满足时通过电子邮件、Slack 或其他连接器接收告警。",
-    "xpack.triggersActionsUI.sections.alertsList.emptyTitle": "创建您的首个告警",
+    "xpack.triggersActionsUI.components.emptyPrompt.emptyButton": "创建告警",
+    "xpack.triggersActionsUI.components.emptyPrompt.emptyDesc": "触发条件满足时通过电子邮件、Slack 或其他连接器接收告警。",
+    "xpack.triggersActionsUI.components.emptyPrompt.emptyTitle": "创建您的首个告警",
     "xpack.triggersActionsUI.sections.alertsList.multipleTitle": "告警",
     "xpack.triggersActionsUI.sections.alertsList.searchPlaceholderTitle": "搜索",
     "xpack.triggersActionsUI.sections.alertsList.singleTitle": "告警",
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.test.tsx
deleted file mode 100644
index 85699cfbd750f..0000000000000
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.test.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import React, { Fragment } from 'react';
-import { shallow, ShallowWrapper } from 'enzyme';
-import { AlertActionSecurityCallOut } from './alert_action_security_call_out';
-
-import { EuiCallOut, EuiButton } from '@elastic/eui';
-import { act } from 'react-dom/test-utils';
-import { httpServiceMock } from '../../../../../../src/core/public/mocks';
-
-const docLinks = { ELASTIC_WEBSITE_URL: 'elastic.co/', DOC_LINK_VERSION: 'current' };
-
-const http = httpServiceMock.createStartContract();
-
-describe('alert action security call out', () => {
-  let useEffect: any;
-
-  const mockUseEffect = () => {
-    // make react execute useEffects despite shallow rendering
-    useEffect.mockImplementationOnce((f: Function) => f());
-  };
-
-  beforeEach(() => {
-    jest.resetAllMocks();
-    useEffect = jest.spyOn(React, 'useEffect');
-    mockUseEffect();
-  });
-
-  test('renders nothing while health is loading', async () => {
-    http.get.mockImplementationOnce(() => new Promise(() => {}));
-
-    let component: ShallowWrapper | undefined;
-    await act(async () => {
-      component = shallow(
-        <AlertActionSecurityCallOut action="created" http={http} docLinks={docLinks} />
-      );
-    });
-
-    expect(component?.is(Fragment)).toBeTruthy();
-    expect(component?.html()).toBe('');
-  });
-
-  test('renders nothing if keys are enabled', async () => {
-    http.get.mockResolvedValue({ isSufficientlySecure: true });
-
-    let component: ShallowWrapper | undefined;
-    await act(async () => {
-      component = shallow(
-        <AlertActionSecurityCallOut action="created" http={http} docLinks={docLinks} />
-      );
-    });
-
-    expect(component?.is(Fragment)).toBeTruthy();
-    expect(component?.html()).toBe('');
-  });
-
-  test('renders the callout if keys are disabled', async () => {
-    http.get.mockResolvedValue({ isSufficientlySecure: false });
-
-    let component: ShallowWrapper | undefined;
-    await act(async () => {
-      component = shallow(
-        <AlertActionSecurityCallOut action="creation" http={http} docLinks={docLinks} />
-      );
-    });
-
-    expect(component?.find(EuiCallOut).prop('title')).toMatchInlineSnapshot(
-      `"Alert creation requires TLS between Elasticsearch and Kibana."`
-    );
-
-    expect(component?.find(EuiButton).prop('href')).toMatchInlineSnapshot(
-      `"elastic.co/guide/en/kibana/current/configuring-tls.html"`
-    );
-  });
-});
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.tsx
deleted file mode 100644
index f7a80202dff89..0000000000000
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/alert_action_security_call_out.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React, { Fragment } from 'react';
-import { Option, none, some, fold, filter } from 'fp-ts/lib/Option';
-import { pipe } from 'fp-ts/lib/pipeable';
-
-import { EuiCallOut, EuiButton, EuiSpacer } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import { FormattedMessage } from '@kbn/i18n/react';
-
-import { DocLinksStart, HttpSetup } from 'kibana/public';
-import { AlertingFrameworkHealth } from '../../types';
-import { health } from '../lib/alert_api';
-
-interface Props {
-  docLinks: Pick<DocLinksStart, 'ELASTIC_WEBSITE_URL' | 'DOC_LINK_VERSION'>;
-  action: string;
-  http: HttpSetup;
-}
-
-export const AlertActionSecurityCallOut: React.FunctionComponent<Props> = ({
-  http,
-  action,
-  docLinks,
-}) => {
-  const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
-
-  const [alertingHealth, setAlertingHealth] = React.useState<Option<AlertingFrameworkHealth>>(none);
-
-  React.useEffect(() => {
-    async function fetchSecurityConfigured() {
-      setAlertingHealth(some(await health({ http })));
-    }
-
-    fetchSecurityConfigured();
-  }, [http]);
-
-  return pipe(
-    alertingHealth,
-    filter(healthCheck => !healthCheck.isSufficientlySecure),
-    fold(
-      () => <Fragment />,
-      () => (
-        <Fragment>
-          <EuiCallOut
-            title={i18n.translate(
-              'xpack.triggersActionsUI.components.alertActionSecurityCallOut.tlsDisabledTitle',
-              {
-                defaultMessage: 'Alert {action} requires TLS between Elasticsearch and Kibana.',
-                values: {
-                  action,
-                },
-              }
-            )}
-            color="warning"
-            size="s"
-            iconType="iInCircle"
-          >
-            <EuiButton
-              color="warning"
-              href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/configuring-tls.html`}
-            >
-              <FormattedMessage
-                id="xpack.triggersActionsUI.components.alertActionSecurityCallOut.enableTlsCta"
-                defaultMessage="Enable TLS"
-              />
-            </EuiButton>
-          </EuiCallOut>
-          <EuiSpacer />
-        </Fragment>
-      )
-    )
-  );
-};
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.scss b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.scss
new file mode 100644
index 0000000000000..c4d12221e3a01
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.scss
@@ -0,0 +1,13 @@
+@mixin padBannerWith($size) {
+  padding-left: $size;
+  padding-right: $size;
+}
+
+.alertingHealthCheck__body {
+  @include padBannerWith(2 * $euiSize);
+}
+
+.alertingFlyoutHealthCheck__body {
+  @include padBannerWith(2 * $euiSize);
+  margin-top: $euiSize;
+}
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
new file mode 100644
index 0000000000000..5156a6146f3a1
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
@@ -0,0 +1,131 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React from 'react';
+import { render } from '@testing-library/react';
+
+import { HealthCheck } from './health_check';
+
+import { act } from 'react-dom/test-utils';
+import { httpServiceMock } from '../../../../../../src/core/public/mocks';
+
+const docLinks = { ELASTIC_WEBSITE_URL: 'elastic.co/', DOC_LINK_VERSION: 'current' };
+
+const http = httpServiceMock.createStartContract();
+
+describe('health check', () => {
+  test('renders spinner while health is loading', async () => {
+    http.get.mockImplementationOnce(() => new Promise(() => {}));
+
+    const { queryByText, container } = render(
+      <HealthCheck http={http} docLinks={docLinks}>
+        <p>{'shouldnt render'}</p>
+      </HealthCheck>
+    );
+    await act(async () => {
+      // wait for useEffect to run
+    });
+
+    expect(container.getElementsByClassName('euiLoadingSpinner').length).toBe(1);
+    expect(queryByText('shouldnt render')).not.toBeInTheDocument();
+  });
+
+  it('renders children if keys are enabled', async () => {
+    http.get.mockResolvedValue({ isSufficientlySecure: true, hasPermanentEncryptionKey: true });
+
+    const { queryByText } = render(
+      <HealthCheck http={http} docLinks={docLinks}>
+        <p>{'should render'}</p>
+      </HealthCheck>
+    );
+    await act(async () => {
+      // wait for useEffect to run
+    });
+    expect(queryByText('should render')).toBeInTheDocument();
+  });
+
+  test('renders warning if keys are disabled', async () => {
+    http.get.mockImplementationOnce(async () => ({
+      isSufficientlySecure: false,
+      hasPermanentEncryptionKey: true,
+    }));
+
+    const { queryAllByText } = render(
+      <HealthCheck http={http} docLinks={docLinks}>
+        <p>{'should render'}</p>
+      </HealthCheck>
+    );
+    await act(async () => {
+      // wait for useEffect to run
+    });
+
+    const [description, action] = queryAllByText(/TLS/i);
+
+    expect(description.textContent).toMatchInlineSnapshot(
+      `"Alerting relies on API keys, which require TLS between Elasticsearch and Kibana. Learn how to enable TLS."`
+    );
+
+    expect(action.textContent).toMatchInlineSnapshot(`"Learn how to enable TLS."`);
+
+    expect(action.getAttribute('href')).toMatchInlineSnapshot(
+      `"elastic.co/guide/en/kibana/current/configuring-tls.html"`
+    );
+  });
+
+  test('renders warning if encryption key is ephemeral', async () => {
+    http.get.mockImplementationOnce(async () => ({
+      isSufficientlySecure: true,
+      hasPermanentEncryptionKey: false,
+    }));
+
+    const { queryByText, queryByRole } = render(
+      <HealthCheck http={http} docLinks={docLinks}>
+        <p>{'should render'}</p>
+      </HealthCheck>
+    );
+    await act(async () => {
+      // wait for useEffect to run
+    });
+
+    const description = queryByRole(/banner/i);
+    expect(description!.textContent).toMatchInlineSnapshot(
+      `"To create an alert, set a value for xpack.encrypted_saved_objects.encryptionKey in your kibana.yml file. Learn how."`
+    );
+
+    const action = queryByText(/Learn/i);
+    expect(action!.textContent).toMatchInlineSnapshot(`"Learn how."`);
+    expect(action!.getAttribute('href')).toMatchInlineSnapshot(
+      `"elastic.co/guide/en/kibana/current/alert-action-settings-kb.html#general-alert-action-settings"`
+    );
+  });
+
+  test('renders warning if encryption key is ephemeral and keys are disabled', async () => {
+    http.get.mockImplementationOnce(async () => ({
+      isSufficientlySecure: false,
+      hasPermanentEncryptionKey: false,
+    }));
+
+    const { queryByText } = render(
+      <HealthCheck http={http} docLinks={docLinks}>
+        <p>{'should render'}</p>
+      </HealthCheck>
+    );
+    await act(async () => {
+      // wait for useEffect to run
+    });
+
+    const description = queryByText(/Transport Layer Security/i);
+
+    expect(description!.textContent).toMatchInlineSnapshot(
+      `"You must enable Transport Layer Security between Kibana and Elasticsearch and configure an encryption key in your kibana.yml file. Learn how"`
+    );
+
+    const action = queryByText(/Learn/i);
+    expect(action!.textContent).toMatchInlineSnapshot(`"Learn how"`);
+    expect(action!.getAttribute('href')).toMatchInlineSnapshot(
+      `"elastic.co/guide/en/kibana/current/alerting-getting-started.html#alerting-setup-prerequisites"`
+    );
+  });
+});
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx
new file mode 100644
index 0000000000000..c967cf5de0771
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx
@@ -0,0 +1,197 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { Fragment } from 'react';
+import { Option, none, some, fold } from 'fp-ts/lib/Option';
+import { pipe } from 'fp-ts/lib/pipeable';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+import { EuiLink, EuiLoadingSpinner } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+
+import { DocLinksStart, HttpSetup } from 'kibana/public';
+
+import { EuiEmptyPrompt, EuiCode } from '@elastic/eui';
+import { AlertingFrameworkHealth } from '../../types';
+import { health } from '../lib/alert_api';
+import './health_check.scss';
+
+interface Props {
+  docLinks: Pick<DocLinksStart, 'ELASTIC_WEBSITE_URL' | 'DOC_LINK_VERSION'>;
+  http: HttpSetup;
+  inFlyout?: boolean;
+}
+
+export const HealthCheck: React.FunctionComponent<Props> = ({
+  docLinks,
+  http,
+  children,
+  inFlyout = false,
+}) => {
+  const [alertingHealth, setAlertingHealth] = React.useState<Option<AlertingFrameworkHealth>>(none);
+
+  React.useEffect(() => {
+    (async function() {
+      setAlertingHealth(some(await health({ http })));
+    })();
+  }, [http]);
+
+  const className = inFlyout ? 'alertingFlyoutHealthCheck' : 'alertingHealthCheck';
+
+  return pipe(
+    alertingHealth,
+    fold(
+      () => <EuiLoadingSpinner size="m" />,
+      healthCheck => {
+        return healthCheck?.isSufficientlySecure && healthCheck?.hasPermanentEncryptionKey ? (
+          <Fragment>{children}</Fragment>
+        ) : !healthCheck.isSufficientlySecure && !healthCheck.hasPermanentEncryptionKey ? (
+          <TlsAndEncryptionError docLinks={docLinks} className={className} />
+        ) : !healthCheck.hasPermanentEncryptionKey ? (
+          <EncryptionError docLinks={docLinks} className={className} />
+        ) : (
+          <TlsError docLinks={docLinks} className={className} />
+        );
+      }
+    )
+  );
+};
+
+type PromptErrorProps = Pick<Props, 'docLinks'> & {
+  className?: string;
+};
+
+const TlsAndEncryptionError = ({
+  docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
+  className,
+}: PromptErrorProps) => (
+  <EuiEmptyPrompt
+    iconType="watchesApp"
+    data-test-subj="actionNeededEmptyPrompt"
+    className={className}
+    titleSize="xs"
+    title={
+      <h2>
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorTitle"
+          defaultMessage="Additional setup required"
+        />
+      </h2>
+    }
+    body={
+      <div className={`${className}__body`}>
+        <p role="banner">
+          {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionError', {
+            defaultMessage:
+              'You must enable Transport Layer Security between Kibana and Elasticsearch and configure an encryption key in your kibana.yml file. ',
+          })}
+          <EuiLink
+            href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alerting-getting-started.html#alerting-setup-prerequisites`}
+            external
+            target="_blank"
+          >
+            {i18n.translate(
+              'xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorAction',
+              {
+                defaultMessage: 'Learn how',
+              }
+            )}
+          </EuiLink>
+        </p>
+      </div>
+    }
+  />
+);
+
+const EncryptionError = ({
+  docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
+  className,
+}: PromptErrorProps) => (
+  <EuiEmptyPrompt
+    iconType="watchesApp"
+    data-test-subj="actionNeededEmptyPrompt"
+    className={className}
+    titleSize="xs"
+    title={
+      <h2>
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.healthCheck.encryptionErrorTitle"
+          defaultMessage="You must set an encryption key"
+        />
+      </h2>
+    }
+    body={
+      <div className={`${className}__body`}>
+        <p role="banner">
+          {i18n.translate(
+            'xpack.triggersActionsUI.components.healthCheck.encryptionErrorBeforeKey',
+            {
+              defaultMessage: 'To create an alert, set a value for ',
+            }
+          )}
+          <EuiCode>{'xpack.encrypted_saved_objects.encryptionKey'}</EuiCode>
+          {i18n.translate(
+            'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey',
+            {
+              defaultMessage: ' in your kibana.yml file. ',
+            }
+          )}
+          <EuiLink
+            href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-action-settings-kb.html#general-alert-action-settings`}
+            external
+            target="_blank"
+          >
+            {i18n.translate(
+              'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAction',
+              {
+                defaultMessage: 'Learn how.',
+              }
+            )}
+          </EuiLink>
+        </p>
+      </div>
+    }
+  />
+);
+
+const TlsError = ({
+  docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
+  className,
+}: PromptErrorProps) => (
+  <EuiEmptyPrompt
+    iconType="watchesApp"
+    data-test-subj="actionNeededEmptyPrompt"
+    className={className}
+    titleSize="xs"
+    title={
+      <h2>
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.healthCheck.tlsErrorTitle"
+          defaultMessage="You must enable Transport Layer Security"
+        />
+      </h2>
+    }
+    body={
+      <div className={`${className}__body`}>
+        <p role="banner">
+          {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsError', {
+            defaultMessage:
+              'Alerting relies on API keys, which require TLS between Elasticsearch and Kibana. ',
+          })}
+          <EuiLink
+            href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/configuring-tls.html`}
+            external
+            target="_blank"
+          >
+            {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsErrorAction', {
+              defaultMessage: 'Learn how to enable TLS.',
+            })}
+          </EuiLink>
+        </p>
+      </div>
+    }
+  />
+);
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.scss b/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.scss
new file mode 100644
index 0000000000000..fe001ce294ef4
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.scss
@@ -0,0 +1,3 @@
+.actEmptyConnectorsPrompt__logo + .actEmptyConnectorsPrompt__logo {
+  margin-left: $euiSize;
+}
\ No newline at end of file
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.tsx
new file mode 100644
index 0000000000000..0e956ea56faa9
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_connectors_prompt.tsx
@@ -0,0 +1,55 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { FormattedMessage } from '@kbn/i18n/react';
+import React, { Fragment } from 'react';
+import { EuiButton, EuiEmptyPrompt, EuiIcon, EuiSpacer, EuiTitle } from '@elastic/eui';
+import './empty_connectors_prompt.scss';
+
+export const EmptyConnectorsPrompt = ({ onCTAClicked }: { onCTAClicked: () => void }) => (
+  <EuiEmptyPrompt
+    data-test-subj="createFirstConnectorEmptyPrompt"
+    title={
+      <Fragment>
+        <EuiIcon type="logoSlack" size="xl" className="actEmptyConnectorsPrompt__logo" />
+        <EuiIcon type="logoGmail" size="xl" className="actEmptyConnectorsPrompt__logo" />
+        <EuiIcon type="logoWebhook" size="xl" className="actEmptyConnectorsPrompt__logo" />
+        <EuiSpacer size="s" />
+        <EuiTitle size="m">
+          <h2>
+            <FormattedMessage
+              id="xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionEmptyTitle"
+              defaultMessage="Create your first connector"
+            />
+          </h2>
+        </EuiTitle>
+      </Fragment>
+    }
+    body={
+      <p>
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionEmptyBody"
+          defaultMessage="Configure email, Slack, Elasticsearch, and third-party services that Kibana can trigger."
+        />
+      </p>
+    }
+    actions={
+      <EuiButton
+        data-test-subj="createFirstActionButton"
+        key="create-action"
+        fill
+        iconType="plusInCircle"
+        iconSide="left"
+        onClick={onCTAClicked}
+      >
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.emptyConnectorsPrompt.addActionButtonLabel"
+          defaultMessage="Create connector"
+        />
+      </EuiButton>
+    }
+  />
+);
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_prompt.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_prompt.tsx
new file mode 100644
index 0000000000000..df593d587de3f
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/prompts/empty_prompt.tsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { FormattedMessage } from '@kbn/i18n/react';
+import React from 'react';
+import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
+
+export const EmptyPrompt = ({ onCTAClicked }: { onCTAClicked: () => void }) => (
+  <EuiEmptyPrompt
+    iconType="watchesApp"
+    data-test-subj="createFirstAlertEmptyPrompt"
+    title={
+      <h2>
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.emptyPrompt.emptyTitle"
+          defaultMessage="Create your first alert"
+        />
+      </h2>
+    }
+    body={
+      <p>
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.emptyPrompt.emptyDesc"
+          defaultMessage="Receive an alert through email, Slack, or another connector when a trigger is hit."
+        />
+      </p>
+    }
+    actions={
+      <EuiButton
+        data-test-subj="createFirstAlertButton"
+        key="create-action"
+        fill
+        iconType="plusInCircle"
+        iconSide="left"
+        onClick={onCTAClicked}
+      >
+        <FormattedMessage
+          id="xpack.triggersActionsUI.components.emptyPrompt.emptyButton"
+          defaultMessage="Create alert"
+        />
+      </EuiButton>
+    }
+  />
+);
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.test.tsx
deleted file mode 100644
index 28bc02ec3392f..0000000000000
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import React, { Fragment } from 'react';
-import { shallow, ShallowWrapper } from 'enzyme';
-import { SecurityEnabledCallOut } from './security_call_out';
-
-import { EuiCallOut, EuiButton } from '@elastic/eui';
-import { act } from 'react-dom/test-utils';
-import { httpServiceMock } from '../../../../../../src/core/public/mocks';
-
-const docLinks = { ELASTIC_WEBSITE_URL: 'elastic.co/', DOC_LINK_VERSION: 'current' };
-
-const http = httpServiceMock.createStartContract();
-
-describe('security call out', () => {
-  let useEffect: any;
-
-  const mockUseEffect = () => {
-    // make react execute useEffects despite shallow rendering
-    useEffect.mockImplementationOnce((f: Function) => f());
-  };
-
-  beforeEach(() => {
-    jest.resetAllMocks();
-    useEffect = jest.spyOn(React, 'useEffect');
-    mockUseEffect();
-  });
-
-  test('renders nothing while health is loading', async () => {
-    http.get.mockImplementationOnce(() => new Promise(() => {}));
-
-    let component: ShallowWrapper | undefined;
-    await act(async () => {
-      component = shallow(<SecurityEnabledCallOut http={http} docLinks={docLinks} />);
-    });
-
-    expect(component?.is(Fragment)).toBeTruthy();
-    expect(component?.html()).toBe('');
-  });
-
-  test('renders nothing if keys are enabled', async () => {
-    http.get.mockResolvedValue({ isSufficientlySecure: true });
-
-    let component: ShallowWrapper | undefined;
-    await act(async () => {
-      component = shallow(<SecurityEnabledCallOut http={http} docLinks={docLinks} />);
-    });
-
-    expect(component?.is(Fragment)).toBeTruthy();
-    expect(component?.html()).toBe('');
-  });
-
-  test('renders the callout if keys are disabled', async () => {
-    http.get.mockImplementationOnce(async () => ({ isSufficientlySecure: false }));
-
-    let component: ShallowWrapper | undefined;
-    await act(async () => {
-      component = shallow(<SecurityEnabledCallOut http={http} docLinks={docLinks} />);
-    });
-
-    expect(component?.find(EuiCallOut).prop('title')).toMatchInlineSnapshot(
-      `"Enable Transport Layer Security"`
-    );
-
-    expect(component?.find(EuiButton).prop('href')).toMatchInlineSnapshot(
-      `"elastic.co/guide/en/kibana/current/configuring-tls.html"`
-    );
-  });
-});
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.tsx
deleted file mode 100644
index 9874a3a0697d2..0000000000000
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/security_call_out.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React, { Fragment } from 'react';
-import { Option, none, some, fold, filter } from 'fp-ts/lib/Option';
-import { pipe } from 'fp-ts/lib/pipeable';
-
-import { EuiCallOut, EuiButton, EuiSpacer } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import { FormattedMessage } from '@kbn/i18n/react';
-
-import { DocLinksStart, HttpSetup } from 'kibana/public';
-
-import { AlertingFrameworkHealth } from '../../types';
-import { health } from '../lib/alert_api';
-
-interface Props {
-  docLinks: Pick<DocLinksStart, 'ELASTIC_WEBSITE_URL' | 'DOC_LINK_VERSION'>;
-  http: HttpSetup;
-}
-
-export const SecurityEnabledCallOut: React.FunctionComponent<Props> = ({ docLinks, http }) => {
-  const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
-
-  const [alertingHealth, setAlertingHealth] = React.useState<Option<AlertingFrameworkHealth>>(none);
-
-  React.useEffect(() => {
-    async function fetchSecurityConfigured() {
-      setAlertingHealth(some(await health({ http })));
-    }
-
-    fetchSecurityConfigured();
-  }, [http]);
-
-  return pipe(
-    alertingHealth,
-    filter(healthCheck => !healthCheck?.isSufficientlySecure),
-    fold(
-      () => <Fragment />,
-      () => (
-        <Fragment>
-          <EuiCallOut
-            title={i18n.translate(
-              'xpack.triggersActionsUI.components.securityCallOut.tlsDisabledTitle',
-              {
-                defaultMessage: 'Enable Transport Layer Security',
-              }
-            )}
-            color="primary"
-            iconType="iInCircle"
-          >
-            <p>
-              <FormattedMessage
-                id="xpack.triggersActionsUI.components.securityCallOut.tlsDisabledDescription"
-                defaultMessage="Alerting relies on API keys, which require TLS between Elasticsearch and Kibana."
-              />
-            </p>
-            <EuiButton
-              href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/configuring-tls.html`}
-            >
-              <FormattedMessage
-                id="xpack.triggersActionsUI.components.securityCallOut.enableTlsCta"
-                defaultMessage="Enable TLS"
-              />
-            </EuiButton>
-          </EuiCallOut>
-          <EuiSpacer />
-        </Fragment>
-      )
-    )
-  );
-};
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/home.tsx b/x-pack/plugins/triggers_actions_ui/public/application/home.tsx
index 7c8d798984bf2..4d0a9980f2231 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/home.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/home.tsx
@@ -29,8 +29,8 @@ import { hasShowActionsCapability, hasShowAlertsCapability } from './lib/capabil
 
 import { ActionsConnectorsList } from './sections/actions_connectors_list/components/actions_connectors_list';
 import { AlertsList } from './sections/alerts_list/components/alerts_list';
-import { SecurityEnabledCallOut } from './components/security_call_out';
 import { PLUGIN } from './constants/plugin';
+import { HealthCheck } from './components/health_check';
 
 interface MatchParams {
   section: Section;
@@ -88,7 +88,6 @@ export const TriggersActionsUIHome: React.FunctionComponent<RouteComponentProps<
   return (
     <EuiPageBody>
       <EuiPageContent>
-        <SecurityEnabledCallOut docLinks={docLinks} http={http} />
         <EuiPageContentHeader>
           <EuiPageContentHeaderSection>
             <EuiTitle size="m">
@@ -142,9 +141,27 @@ export const TriggersActionsUIHome: React.FunctionComponent<RouteComponentProps<
 
         <Switch>
           {canShowActions && (
-            <Route exact path={routeToConnectors} component={ActionsConnectorsList} />
+            <Route
+              exact
+              path={routeToConnectors}
+              component={() => (
+                <HealthCheck docLinks={docLinks} http={http}>
+                  <ActionsConnectorsList />
+                </HealthCheck>
+              )}
+            />
+          )}
+          {canShowAlerts && (
+            <Route
+              exact
+              path={routeToAlerts}
+              component={() => (
+                <HealthCheck docLinks={docLinks} http={http}>
+                  <AlertsList />
+                </HealthCheck>
+              )}
+            />
           )}
-          {canShowAlerts && <Route exact path={routeToAlerts} component={AlertsList} />}
         </Switch>
       </EuiPageContent>
     </EuiPageBody>
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss
index 3d65b8a799b1b..70ad1cae6c1d1 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss
@@ -1,7 +1,3 @@
-.actConnectorsList__logo + .actConnectorsList__logo {
-  margin-left: $euiSize;
-}
-
 .actConnectorsList__tableRowDisabled {
   background-color: $euiColorLightestShade;
 
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx
index 81693e1d2d9d1..47e058f473946 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx
@@ -10,9 +10,6 @@ import {
   EuiInMemoryTable,
   EuiSpacer,
   EuiButton,
-  EuiIcon,
-  EuiEmptyPrompt,
-  EuiTitle,
   EuiLink,
   EuiLoadingSpinner,
   EuiIconTip,
@@ -30,6 +27,7 @@ import { ActionsConnectorsContextProvider } from '../../../context/actions_conne
 import { checkActionTypeEnabled } from '../../../lib/check_action_type_enabled';
 import './actions_connectors_list.scss';
 import { ActionConnector, ActionConnectorTableItem, ActionTypeIndex } from '../../../../types';
+import { EmptyConnectorsPrompt } from '../../../components/prompts/empty_connectors_prompt';
 
 export const ActionsConnectorsList: React.FunctionComponent = () => {
   const { http, toastNotifications, capabilities, actionTypeRegistry } = useAppDependencies();
@@ -324,51 +322,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => {
     />
   );
 
-  const emptyPrompt = (
-    <EuiEmptyPrompt
-      data-test-subj="createFirstConnectorEmptyPrompt"
-      title={
-        <Fragment>
-          <EuiIcon type="logoSlack" size="xl" className="actConnectorsList__logo" />
-          <EuiIcon type="logoGmail" size="xl" className="actConnectorsList__logo" />
-          <EuiIcon type="logoWebhook" size="xl" className="actConnectorsList__logo" />
-          <EuiSpacer size="s" />
-          <EuiTitle size="m">
-            <h2>
-              <FormattedMessage
-                id="xpack.triggersActionsUI.sections.actionsConnectorsList.addActionEmptyTitle"
-                defaultMessage="Create your first connector"
-              />
-            </h2>
-          </EuiTitle>
-        </Fragment>
-      }
-      body={
-        <p>
-          <FormattedMessage
-            id="xpack.triggersActionsUI.sections.actionsConnectorsList.addActionEmptyBody"
-            defaultMessage="Configure email, Slack, Elasticsearch, and third-party services that Kibana can trigger."
-          />
-        </p>
-      }
-      actions={
-        <EuiButton
-          data-test-subj="createFirstActionButton"
-          key="create-action"
-          fill
-          iconType="plusInCircle"
-          iconSide="left"
-          onClick={() => setAddFlyoutVisibility(true)}
-        >
-          <FormattedMessage
-            id="xpack.triggersActionsUI.sections.actionsConnectorsList.addActionButtonLabel"
-            defaultMessage="Create connector"
-          />
-        </EuiButton>
-      }
-    />
-  );
-
   const noPermissionPrompt = (
     <h2>
       <FormattedMessage
@@ -420,7 +373,9 @@ export const ActionsConnectorsList: React.FunctionComponent = () => {
         </EuiFlexGroup>
       )}
       {data.length !== 0 && table}
-      {data.length === 0 && canSave && !isLoadingActions && !isLoadingActionTypes && emptyPrompt}
+      {data.length === 0 && canSave && !isLoadingActions && !isLoadingActionTypes && (
+        <EmptyConnectorsPrompt onCTAClicked={() => setAddFlyoutVisibility(true)} />
+      )}
       {data.length === 0 && !canSave && noPermissionPrompt}
       <ActionsConnectorsContextProvider
         value={{
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx
index ff83737325e8b..c1f8b0e383171 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx
@@ -53,7 +53,10 @@ describe('alert_add', () => {
       docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' },
     };
 
-    mockes.http.get.mockResolvedValue({ isSufficientlySecure: true });
+    mockes.http.get.mockResolvedValue({
+      isSufficientlySecure: true,
+      hasPermanentEncryptionKey: true,
+    });
 
     const alertType = {
       id: 'my-alert-type',
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx
index e025248fad52e..0620ced6365a9 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx
@@ -25,7 +25,7 @@ import { Alert, AlertAction, IErrorObject } from '../../../types';
 import { AlertForm, validateBaseProperties } from './alert_form';
 import { alertReducer } from './alert_reducer';
 import { createAlert } from '../../lib/alert_api';
-import { AlertActionSecurityCallOut } from '../../components/alert_action_security_call_out';
+import { HealthCheck } from '../../components/health_check';
 import { PLUGIN } from '../../constants/plugin';
 
 interface AlertAddProps {
@@ -154,62 +154,54 @@ export const AlertAdd = ({
             </h3>
           </EuiTitle>
         </EuiFlyoutHeader>
-        <AlertActionSecurityCallOut
-          docLinks={docLinks}
-          action={i18n.translate(
-            'xpack.triggersActionsUI.sections.alertAdd.securityCalloutAction',
-            {
-              defaultMessage: 'creation',
-            }
-          )}
-          http={http}
-        />
-        <EuiFlyoutBody>
-          <AlertForm
-            alert={alert}
-            dispatch={dispatch}
-            errors={errors}
-            canChangeTrigger={canChangeTrigger}
-          />
-        </EuiFlyoutBody>
-        <EuiFlyoutFooter>
-          <EuiFlexGroup justifyContent="spaceBetween">
-            <EuiFlexItem grow={false}>
-              <EuiButtonEmpty data-test-subj="cancelSaveAlertButton" onClick={closeFlyout}>
-                {i18n.translate('xpack.triggersActionsUI.sections.alertAdd.cancelButtonLabel', {
-                  defaultMessage: 'Cancel',
-                })}
-              </EuiButtonEmpty>
-            </EuiFlexItem>
-            <EuiFlexItem grow={false}>
-              <EuiButton
-                fill
-                color="secondary"
-                data-test-subj="saveAlertButton"
-                type="submit"
-                iconType="check"
-                isDisabled={hasErrors || hasActionErrors}
-                isLoading={isSaving}
-                onClick={async () => {
-                  setIsSaving(true);
-                  const savedAlert = await onSaveAlert();
-                  setIsSaving(false);
-                  if (savedAlert) {
-                    closeFlyout();
-                    if (reloadAlerts) {
-                      reloadAlerts();
+        <HealthCheck docLinks={docLinks} http={http} inFlyout={true}>
+          <EuiFlyoutBody>
+            <AlertForm
+              alert={alert}
+              dispatch={dispatch}
+              errors={errors}
+              canChangeTrigger={canChangeTrigger}
+            />
+          </EuiFlyoutBody>
+          <EuiFlyoutFooter>
+            <EuiFlexGroup justifyContent="spaceBetween">
+              <EuiFlexItem grow={false}>
+                <EuiButtonEmpty data-test-subj="cancelSaveAlertButton" onClick={closeFlyout}>
+                  {i18n.translate('xpack.triggersActionsUI.sections.alertAdd.cancelButtonLabel', {
+                    defaultMessage: 'Cancel',
+                  })}
+                </EuiButtonEmpty>
+              </EuiFlexItem>
+              <EuiFlexItem grow={false}>
+                <EuiButton
+                  fill
+                  color="secondary"
+                  data-test-subj="saveAlertButton"
+                  type="submit"
+                  iconType="check"
+                  isDisabled={hasErrors || hasActionErrors}
+                  isLoading={isSaving}
+                  onClick={async () => {
+                    setIsSaving(true);
+                    const savedAlert = await onSaveAlert();
+                    setIsSaving(false);
+                    if (savedAlert) {
+                      closeFlyout();
+                      if (reloadAlerts) {
+                        reloadAlerts();
+                      }
                     }
-                  }
-                }}
-              >
-                <FormattedMessage
-                  id="xpack.triggersActionsUI.sections.alertAdd.saveButtonLabel"
-                  defaultMessage="Save"
-                />
-              </EuiButton>
-            </EuiFlexItem>
-          </EuiFlexGroup>
-        </EuiFlyoutFooter>
+                  }}
+                >
+                  <FormattedMessage
+                    id="xpack.triggersActionsUI.sections.alertAdd.saveButtonLabel"
+                    defaultMessage="Save"
+                  />
+                </EuiButton>
+              </EuiFlexItem>
+            </EuiFlexGroup>
+          </EuiFlyoutFooter>
+        </HealthCheck>
       </EuiFlyout>
     </EuiPortal>
   );
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx
index 6fcfb463c4c77..916ba368e0732 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx
@@ -36,7 +36,10 @@ describe('alert_edit', () => {
       docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' },
     };
 
-    mockedCoreSetup.http.get.mockResolvedValue({ isSufficientlySecure: true });
+    mockedCoreSetup.http.get.mockResolvedValue({
+      isSufficientlySecure: true,
+      hasPermanentEncryptionKey: true,
+    });
 
     const alertType = {
       id: 'my-alert-type',
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx
index 3f27a7860bafa..4255eca83be47 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx
@@ -26,7 +26,7 @@ import { Alert, AlertAction, IErrorObject } from '../../../types';
 import { AlertForm, validateBaseProperties } from './alert_form';
 import { alertReducer } from './alert_reducer';
 import { updateAlert } from '../../lib/alert_api';
-import { AlertActionSecurityCallOut } from '../../components/alert_action_security_call_out';
+import { HealthCheck } from '../../components/health_check';
 import { PLUGIN } from '../../constants/plugin';
 
 interface AlertEditProps {
@@ -137,77 +137,69 @@ export const AlertEdit = ({
             </h3>
           </EuiTitle>
         </EuiFlyoutHeader>
-        <AlertActionSecurityCallOut
-          docLinks={docLinks}
-          action={i18n.translate(
-            'xpack.triggersActionsUI.sections.alertEdit.securityCalloutAction',
-            {
-              defaultMessage: 'editing',
-            }
-          )}
-          http={http}
-        />
-        <EuiFlyoutBody>
-          {hasActionsDisabled && (
-            <Fragment>
-              <EuiCallOut
-                size="s"
-                color="danger"
-                iconType="alert"
-                title={i18n.translate(
-                  'xpack.triggersActionsUI.sections.alertEdit.disabledActionsWarningTitle',
-                  { defaultMessage: 'This alert has actions that are disabled' }
-                )}
-              />
-              <EuiSpacer />
-            </Fragment>
-          )}
-          <AlertForm
-            alert={alert}
-            dispatch={dispatch}
-            errors={errors}
-            canChangeTrigger={false}
-            setHasActionsDisabled={setHasActionsDisabled}
-          />
-        </EuiFlyoutBody>
-        <EuiFlyoutFooter>
-          <EuiFlexGroup justifyContent="spaceBetween">
-            <EuiFlexItem grow={false}>
-              <EuiButtonEmpty data-test-subj="cancelSaveEditedAlertButton" onClick={closeFlyout}>
-                {i18n.translate('xpack.triggersActionsUI.sections.alertEdit.cancelButtonLabel', {
-                  defaultMessage: 'Cancel',
-                })}
-              </EuiButtonEmpty>
-            </EuiFlexItem>
-            <EuiFlexItem grow={false}>
-              <EuiButton
-                fill
-                color="secondary"
-                data-test-subj="saveEditedAlertButton"
-                type="submit"
-                iconType="check"
-                isDisabled={hasErrors || hasActionErrors}
-                isLoading={isSaving}
-                onClick={async () => {
-                  setIsSaving(true);
-                  const savedAlert = await onSaveAlert();
-                  setIsSaving(false);
-                  if (savedAlert) {
-                    closeFlyout();
-                    if (reloadAlerts) {
-                      reloadAlerts();
-                    }
-                  }
-                }}
-              >
-                <FormattedMessage
-                  id="xpack.triggersActionsUI.sections.alertEdit.saveButtonLabel"
-                  defaultMessage="Save"
+        <HealthCheck docLinks={docLinks} http={http} inFlyout={true}>
+          <EuiFlyoutBody>
+            {hasActionsDisabled && (
+              <Fragment>
+                <EuiCallOut
+                  size="s"
+                  color="danger"
+                  iconType="alert"
+                  title={i18n.translate(
+                    'xpack.triggersActionsUI.sections.alertEdit.disabledActionsWarningTitle',
+                    { defaultMessage: 'This alert has actions that are disabled' }
+                  )}
                 />
-              </EuiButton>
-            </EuiFlexItem>
-          </EuiFlexGroup>
-        </EuiFlyoutFooter>
+                <EuiSpacer />
+              </Fragment>
+            )}
+            <AlertForm
+              alert={alert}
+              dispatch={dispatch}
+              errors={errors}
+              canChangeTrigger={false}
+              setHasActionsDisabled={setHasActionsDisabled}
+            />
+          </EuiFlyoutBody>
+          <EuiFlyoutFooter>
+            <EuiFlexGroup justifyContent="spaceBetween">
+              <EuiFlexItem grow={false}>
+                <EuiButtonEmpty data-test-subj="cancelSaveEditedAlertButton" onClick={closeFlyout}>
+                  {i18n.translate('xpack.triggersActionsUI.sections.alertEdit.cancelButtonLabel', {
+                    defaultMessage: 'Cancel',
+                  })}
+                </EuiButtonEmpty>
+              </EuiFlexItem>
+              <EuiFlexItem grow={false}>
+                <EuiButton
+                  fill
+                  color="secondary"
+                  data-test-subj="saveEditedAlertButton"
+                  type="submit"
+                  iconType="check"
+                  isDisabled={hasErrors || hasActionErrors}
+                  isLoading={isSaving}
+                  onClick={async () => {
+                    setIsSaving(true);
+                    const savedAlert = await onSaveAlert();
+                    setIsSaving(false);
+                    if (savedAlert) {
+                      closeFlyout();
+                      if (reloadAlerts) {
+                        reloadAlerts();
+                      }
+                    }
+                  }}
+                >
+                  <FormattedMessage
+                    id="xpack.triggersActionsUI.sections.alertEdit.saveButtonLabel"
+                    defaultMessage="Save"
+                  />
+                </EuiButton>
+              </EuiFlexItem>
+            </EuiFlexGroup>
+          </EuiFlyoutFooter>
+        </HealthCheck>
       </EuiFlyout>
     </EuiPortal>
   );
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx
index afd3299f0c2bb..5d59180ff572b 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx
@@ -15,7 +15,6 @@ import {
   EuiFlexItem,
   EuiIcon,
   EuiSpacer,
-  EuiEmptyPrompt,
   EuiLink,
   EuiLoadingSpinner,
 } from '@elastic/eui';
@@ -36,6 +35,7 @@ import { loadActionTypes } from '../../../lib/action_connector_api';
 import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib/capabilities';
 import { routeToAlertDetails, DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants';
 import { DeleteModalConfirmation } from '../../../components/delete_modal_confirmation';
+import { EmptyPrompt } from '../../../components/prompts/empty_prompt';
 
 const ENTER_KEY = 13;
 
@@ -292,44 +292,6 @@ export const AlertsList: React.FunctionComponent = () => {
     );
   }
 
-  const emptyPrompt = (
-    <EuiEmptyPrompt
-      iconType="watchesApp"
-      data-test-subj="createFirstAlertEmptyPrompt"
-      title={
-        <h2>
-          <FormattedMessage
-            id="xpack.triggersActionsUI.sections.alertsList.emptyTitle"
-            defaultMessage="Create your first alert"
-          />
-        </h2>
-      }
-      body={
-        <p>
-          <FormattedMessage
-            id="xpack.triggersActionsUI.sections.alertsList.emptyDesc"
-            defaultMessage="Receive an alert through email, Slack, or another connector when a trigger is hit."
-          />
-        </p>
-      }
-      actions={
-        <EuiButton
-          data-test-subj="createFirstAlertButton"
-          key="create-action"
-          fill
-          iconType="plusInCircle"
-          iconSide="left"
-          onClick={() => setAlertFlyoutVisibility(true)}
-        >
-          <FormattedMessage
-            id="xpack.triggersActionsUI.sections.alertsList.emptyButton"
-            defaultMessage="Create alert"
-          />
-        </EuiButton>
-      }
-    />
-  );
-
   const table = (
     <Fragment>
       <EuiFlexGroup gutterSize="s">
@@ -473,7 +435,7 @@ export const AlertsList: React.FunctionComponent = () => {
           </EuiFlexItem>
         </EuiFlexGroup>
       ) : (
-        emptyPrompt
+        <EmptyPrompt onCTAClicked={() => setAlertFlyoutVisibility(true)} />
       )}
       <AlertsContextProvider
         value={{

From da51cc041d9cb288d38ac45f2dd1299681bde5a6 Mon Sep 17 00:00:00 2001
From: eyalkoren <41850454+eyalkoren@users.noreply.github.com>
Date: Thu, 9 Apr 2020 00:56:52 +0300
Subject: [PATCH 06/78] [APM] Agent remote configuration: changes in Java
 property descriptions (#62282)

* [APM] Agent remote configuration: changes in Java property descriptions

* Removing newlines

* Update snapshot

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Brandon Morelli <brandon.morelli@elastic.co>
Co-authored-by: Nathan L Smith <smith@nlsmith.com>
---
 .../__snapshots__/index.test.ts.snap                 |  5 +++--
 .../setting_definitions/java_settings.ts             | 12 ++++++------
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap
index bc435179762a2..49840d2157af7 100644
--- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap
+++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap
@@ -153,8 +153,9 @@ Array [
   },
   Object {
     "key": "stress_monitor_gc_stress_threshold",
-    "type": "boolean",
-    "validationName": "(\\"true\\" | \\"false\\")",
+    "type": "float",
+    "validationError": "Must be a number between 0.000 and 1",
+    "validationName": "numberFloatRt",
   },
   Object {
     "key": "stress_monitor_system_cpu_relief_threshold",
diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts
index bb050076b9f9a..2e10c74378549 100644
--- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts
+++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts
@@ -20,7 +20,7 @@ export const javaSettings: RawSettingDefinition[] = [
       'xpack.apm.agentConfig.enableLogCorrelation.description',
       {
         defaultMessage:
-          "A boolean specifying if the agent should integrate into SLF4J's MDC to enable trace-log correlation. If set to `true`, the agent will set the `trace.id` and `transaction.id` for the currently active spans and transactions to the MDC. While it's allowed to enable this setting at runtime, you can't disable it without a restart."
+          "A boolean specifying if the agent should integrate into SLF4J's MDC to enable trace-log correlation. If set to `true`, the agent will set the `trace.id` and `transaction.id` for the currently active spans and transactions to the MDC. Since Java agent version 1.16.0, the agent also adds `error.id` of captured error to the MDC just before the error message is logged. NOTE: While it's allowed to enable this setting at runtime, you can't disable it without a restart."
       }
     ),
     includeAgents: ['java']
@@ -41,7 +41,7 @@ export const javaSettings: RawSettingDefinition[] = [
       'xpack.apm.agentConfig.circuitBreakerEnabled.description',
       {
         defaultMessage:
-          'A boolean specifying whether the circuit breaker should be enabled or not.  When enabled, the agent periodically polls stress monitors to detect system/process/JVM stress state. If ANY of the monitors detects a stress indication, the agent will become inactive, as if the `active` configuration option has been set to `false`, thus reducing resource consumption to a minimum. When inactive, the agent continues polling the same monitors in order to detect whether the stress state has been relieved. If ALL monitors approve that the system/process/JVM is not under stress anymore, the agent will resume and become fully functional.'
+          'A boolean specifying whether the circuit breaker should be enabled or not.  When enabled, the agent periodically polls stress monitors to detect system/process/JVM stress state. If ANY of the monitors detects a stress indication, the agent will pause, as if the `recording` configuration option has been set to `false`, thus reducing resource consumption to a minimum. When paused, the agent continues polling the same monitors in order to detect whether the stress state has been relieved. If ALL monitors approve that the system/process/JVM is not under stress anymore, the agent will resume and become fully functional.'
       }
     ),
     includeAgents: ['java']
@@ -52,7 +52,7 @@ export const javaSettings: RawSettingDefinition[] = [
       'xpack.apm.agentConfig.stressMonitorGcStressThreshold.label',
       { defaultMessage: 'Stress monitor gc stress threshold' }
     ),
-    type: 'boolean',
+    type: 'float',
     category: 'Circuit-Breaker',
     defaultValue: '0.95',
     description: i18n.translate(
@@ -155,7 +155,7 @@ export const javaSettings: RawSettingDefinition[] = [
       'xpack.apm.agentConfig.profilingInferredSpansEnabled.description',
       {
         defaultMessage:
-          'Set to `true` to make the agent create spans for method executions based on async-profiler, a sampling aka statistical profiler. Due to the nature of how sampling profilers work, the duration of the inferred spans are not exact, but only estimations. The `profiling_inferred_spans_sampling_interval` lets you fine tune the trade-off between accuracy and overhead. The inferred spans are created after a profiling session has ended. This means there is a delay between the regular and the inferred spans being visible in the UI. This feature is not available on Windows'
+          'Set to `true` to make the agent create spans for method executions based on async-profiler, a sampling aka statistical profiler. Due to the nature of how sampling profilers work, the duration of the inferred spans are not exact, but only estimations. The `profiling_inferred_spans_sampling_interval` lets you fine tune the trade-off between accuracy and overhead. The inferred spans are created after a profiling session has ended. This means there is a delay between the regular and the inferred spans being visible in the UI. NOTE: This feature is not available on Windows.'
       }
     ),
     includeAgents: ['java']
@@ -209,7 +209,7 @@ export const javaSettings: RawSettingDefinition[] = [
       'xpack.apm.agentConfig.profilingInferredSpansIncludedClasses.description',
       {
         defaultMessage:
-          'If set, the agent will only create inferred spans for methods which match this list. Setting a value may slightly increase performance and can reduce clutter by only creating spans for the classes you are interested in. Example: `org.example.myapp.*` This option supports the wildcard `*`, which matches zero or more characters. Examples: `/foo/*/bar/*/baz*`, `*foo*`. Matching is case insensitive by default. Prepending an element with `(?-i)` makes the matching case sensitive.'
+          'If set, the agent will only create inferred spans for methods which match this list. Setting a value may slightly reduce overhead and can reduce clutter by only creating spans for the classes you are interested in. This option supports the wildcard `*`, which matches zero or more characters. Example: `org.example.myapp.*`. Matching is case insensitive by default. Prepending an element with `(?-i)` makes the matching case sensitive.'
       }
     ),
     includeAgents: ['java']
@@ -228,7 +228,7 @@ export const javaSettings: RawSettingDefinition[] = [
       'xpack.apm.agentConfig.profilingInferredSpansExcludedClasses.description',
       {
         defaultMessage:
-          'Excludes classes for which no profiler-inferred spans should be created. This option supports the wildcard `*`, which matches zero or more characters. Examples: `/foo/*/bar/*/baz*`, `*foo*`. Matching is case insensitive by default. Prepending an element with `(?-i)` makes the matching case sensitive.'
+          'Excludes classes for which no profiler-inferred spans should be created. This option supports the wildcard `*`, which matches zero or more characters. Matching is case insensitive by default. Prepending an element with `(?-i)` makes the matching case sensitive.'
       }
     ),
     includeAgents: ['java']

From 0c35762f2702c813dfb74c37bae4364eecfc95c4 Mon Sep 17 00:00:00 2001
From: Brittany Joiner <brittanyjoiner15@gmail.com>
Date: Wed, 8 Apr 2020 18:08:13 -0500
Subject: [PATCH 07/78] Add Error Exception Type Column (#59596)

* start of error exception type

* width and link

* removed extra line

* updated snapshot

* updated snapshots

* updated snapshots

* Update snapshots

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Nathan L Smith <smith@nlsmith.com>
---
 .../__test__/__snapshots__/List.test.tsx.snap | 287 ++++++++++++++++--
 .../app/ErrorGroupOverview/List/index.tsx     |  36 ++-
 .../elasticsearch_fieldnames.test.ts.snap     |   6 +
 .../apm/common/elasticsearch_fieldnames.ts    |   1 +
 .../errors/__snapshots__/queries.test.ts.snap |   2 +
 .../apm/server/lib/errors/get_error_groups.ts |   6 +-
 6 files changed, 306 insertions(+), 32 deletions(-)

diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap
index 205a303bcf47b..afa0cb51cd108 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap
+++ b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap
@@ -11,6 +11,12 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = `
         "sortable": false,
         "width": "96px",
       },
+      Object {
+        "field": "type",
+        "name": "Type",
+        "render": [Function],
+        "sortable": false,
+      },
       Object {
         "field": "message",
         "name": "Error message and culprit",
@@ -142,7 +148,28 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = `
             </th>
             <th
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_message_1"
+              data-test-subj="tableHeaderCell_type_1"
+              role="columnheader"
+              scope="col"
+              style={
+                Object {
+                  "width": undefined,
+                }
+              }
+            >
+              <div
+                className="euiTableCellContent"
+              >
+                <span
+                  className="euiTableCellContent__text"
+                >
+                  Type
+                </span>
+              </div>
+            </th>
+            <th
+              className="euiTableHeaderCell"
+              data-test-subj="tableHeaderCell_message_2"
               role="columnheader"
               scope="col"
               style={
@@ -163,7 +190,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = `
             </th>
             <td
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_handled_2"
+              data-test-subj="tableHeaderCell_handled_3"
               role="columnheader"
               scope="col"
               style={
@@ -184,7 +211,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = `
               aria-live="polite"
               aria-sort="descending"
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_occurrenceCount_3"
+              data-test-subj="tableHeaderCell_occurrenceCount_4"
               role="columnheader"
               scope="col"
               style={
@@ -225,7 +252,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = `
               aria-live="polite"
               aria-sort="none"
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_latestOccurrenceAt_4"
+              data-test-subj="tableHeaderCell_latestOccurrenceAt_5"
               role="columnheader"
               scope="col"
               style={
@@ -264,7 +291,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = `
           >
             <td
               className="euiTableRowCell euiTableRowCell--isMobileFullWidth"
-              colSpan={5}
+              colSpan={6}
               style={
                 Object {
                   "width": undefined,
@@ -294,6 +321,13 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
   font-family: "Roboto Mono",Consolas,Menlo,Courier,monospace;
 }
 
+.c2 {
+  max-width: 100%;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
 .c1 {
   max-width: 100%;
   white-space: nowrap;
@@ -301,7 +335,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
   text-overflow: ellipsis;
 }
 
-.c2 {
+.c3 {
   font-family: "Roboto Mono",Consolas,Menlo,Courier,monospace;
   font-size: 16px;
   max-width: 100%;
@@ -310,7 +344,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
   text-overflow: ellipsis;
 }
 
-.c3 {
+.c4 {
   font-family: "Roboto Mono",Consolas,Menlo,Courier,monospace;
 }
 
@@ -324,6 +358,12 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
         "sortable": false,
         "width": "96px",
       },
+      Object {
+        "field": "type",
+        "name": "Type",
+        "render": [Function],
+        "sortable": false,
+      },
       Object {
         "field": "message",
         "name": "Error message and culprit",
@@ -486,7 +526,28 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
             </th>
             <th
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_message_1"
+              data-test-subj="tableHeaderCell_type_1"
+              role="columnheader"
+              scope="col"
+              style={
+                Object {
+                  "width": undefined,
+                }
+              }
+            >
+              <div
+                className="euiTableCellContent"
+              >
+                <span
+                  className="euiTableCellContent__text"
+                >
+                  Type
+                </span>
+              </div>
+            </th>
+            <th
+              className="euiTableHeaderCell"
+              data-test-subj="tableHeaderCell_message_2"
               role="columnheader"
               scope="col"
               style={
@@ -507,7 +568,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
             </th>
             <td
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_handled_2"
+              data-test-subj="tableHeaderCell_handled_3"
               role="columnheader"
               scope="col"
               style={
@@ -528,7 +589,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
               aria-live="polite"
               aria-sort="descending"
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_occurrenceCount_3"
+              data-test-subj="tableHeaderCell_occurrenceCount_4"
               role="columnheader"
               scope="col"
               style={
@@ -569,7 +630,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
               aria-live="polite"
               aria-sort="none"
               className="euiTableHeaderCell"
-              data-test-subj="tableHeaderCell_latestOccurrenceAt_4"
+              data-test-subj="tableHeaderCell_latestOccurrenceAt_5"
               role="columnheader"
               scope="col"
               style={
@@ -642,6 +703,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                 </Styled(ErrorDetailLink)>
               </div>
             </td>
+            <td
+              className="euiTableRowCell"
+              style={
+                Object {
+                  "width": undefined,
+                }
+              }
+            >
+              <div
+                className="euiTableRowCell__mobileHeader euiTableRowCell--hideForDesktop"
+              >
+                Type
+              </div>
+              <div
+                className="euiTableCellContent euiTableCellContent--overflowingContent"
+              >
+                <Styled(ErrorOverviewLink)
+                  className=""
+                  query={
+                    Object {
+                      "end": "2018-01-10T10:06:41.050Z",
+                      "kuery": "error.exception.type:undefined",
+                      "page": 0,
+                      "serviceName": "opbeans-python",
+                      "start": "2018-01-10T09:51:41.050Z",
+                      "transactionType": "request",
+                    }
+                  }
+                  serviceName="opbeans-python"
+                >
+                  <EuiLink
+                    className="c1"
+                    href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                  >
+                    <a
+                      className="euiLink euiLink--primary c1"
+                      href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                      rel="noreferrer"
+                    />
+                  </EuiLink>
+                </Styled(ErrorOverviewLink)>
+              </div>
+            </td>
             <td
               className="euiTableRowCell"
               style={
@@ -662,7 +766,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                   className=""
                 >
                   <div
-                    className="c1"
+                    className="c2"
                   >
                     <span
                       className="euiToolTipAnchor"
@@ -676,13 +780,13 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         serviceName="opbeans-python"
                       >
                         <EuiLink
-                          className="c2"
+                          className="c3"
                           href="#/services/opbeans-python/errors/a0ce2c8978ef92cdf2ff163ae28576ee?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
                           <a
-                            className="euiLink euiLink--primary c2"
+                            className="euiLink euiLink--primary c3"
                             href="#/services/opbeans-python/errors/a0ce2c8978ef92cdf2ff163ae28576ee?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                             onBlur={[Function]}
                             onFocus={[Function]}
@@ -704,7 +808,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         onFocus={[Function]}
                       >
                         <div
-                          className="c3"
+                          className="c4"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
@@ -812,6 +916,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                 </Styled(ErrorDetailLink)>
               </div>
             </td>
+            <td
+              className="euiTableRowCell"
+              style={
+                Object {
+                  "width": undefined,
+                }
+              }
+            >
+              <div
+                className="euiTableRowCell__mobileHeader euiTableRowCell--hideForDesktop"
+              >
+                Type
+              </div>
+              <div
+                className="euiTableCellContent euiTableCellContent--overflowingContent"
+              >
+                <Styled(ErrorOverviewLink)
+                  className=""
+                  query={
+                    Object {
+                      "end": "2018-01-10T10:06:41.050Z",
+                      "kuery": "error.exception.type:undefined",
+                      "page": 0,
+                      "serviceName": "opbeans-python",
+                      "start": "2018-01-10T09:51:41.050Z",
+                      "transactionType": "request",
+                    }
+                  }
+                  serviceName="opbeans-python"
+                >
+                  <EuiLink
+                    className="c1"
+                    href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                  >
+                    <a
+                      className="euiLink euiLink--primary c1"
+                      href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                      rel="noreferrer"
+                    />
+                  </EuiLink>
+                </Styled(ErrorOverviewLink)>
+              </div>
+            </td>
             <td
               className="euiTableRowCell"
               style={
@@ -832,7 +979,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                   className=""
                 >
                   <div
-                    className="c1"
+                    className="c2"
                   >
                     <span
                       className="euiToolTipAnchor"
@@ -846,13 +993,13 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         serviceName="opbeans-python"
                       >
                         <EuiLink
-                          className="c2"
+                          className="c3"
                           href="#/services/opbeans-python/errors/f3ac95493913cc7a3cfec30a19d2120a?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
                           <a
-                            className="euiLink euiLink--primary c2"
+                            className="euiLink euiLink--primary c3"
                             href="#/services/opbeans-python/errors/f3ac95493913cc7a3cfec30a19d2120a?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                             onBlur={[Function]}
                             onFocus={[Function]}
@@ -874,7 +1021,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         onFocus={[Function]}
                       >
                         <div
-                          className="c3"
+                          className="c4"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
@@ -982,6 +1129,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                 </Styled(ErrorDetailLink)>
               </div>
             </td>
+            <td
+              className="euiTableRowCell"
+              style={
+                Object {
+                  "width": undefined,
+                }
+              }
+            >
+              <div
+                className="euiTableRowCell__mobileHeader euiTableRowCell--hideForDesktop"
+              >
+                Type
+              </div>
+              <div
+                className="euiTableCellContent euiTableCellContent--overflowingContent"
+              >
+                <Styled(ErrorOverviewLink)
+                  className=""
+                  query={
+                    Object {
+                      "end": "2018-01-10T10:06:41.050Z",
+                      "kuery": "error.exception.type:undefined",
+                      "page": 0,
+                      "serviceName": "opbeans-python",
+                      "start": "2018-01-10T09:51:41.050Z",
+                      "transactionType": "request",
+                    }
+                  }
+                  serviceName="opbeans-python"
+                >
+                  <EuiLink
+                    className="c1"
+                    href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                  >
+                    <a
+                      className="euiLink euiLink--primary c1"
+                      href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                      rel="noreferrer"
+                    />
+                  </EuiLink>
+                </Styled(ErrorOverviewLink)>
+              </div>
+            </td>
             <td
               className="euiTableRowCell"
               style={
@@ -1002,7 +1192,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                   className=""
                 >
                   <div
-                    className="c1"
+                    className="c2"
                   >
                     <span
                       className="euiToolTipAnchor"
@@ -1016,13 +1206,13 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         serviceName="opbeans-python"
                       >
                         <EuiLink
-                          className="c2"
+                          className="c3"
                           href="#/services/opbeans-python/errors/e90863d04b7a692435305f09bbe8c840?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
                           <a
-                            className="euiLink euiLink--primary c2"
+                            className="euiLink euiLink--primary c3"
                             href="#/services/opbeans-python/errors/e90863d04b7a692435305f09bbe8c840?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                             onBlur={[Function]}
                             onFocus={[Function]}
@@ -1044,7 +1234,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         onFocus={[Function]}
                       >
                         <div
-                          className="c3"
+                          className="c4"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
@@ -1152,6 +1342,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                 </Styled(ErrorDetailLink)>
               </div>
             </td>
+            <td
+              className="euiTableRowCell"
+              style={
+                Object {
+                  "width": undefined,
+                }
+              }
+            >
+              <div
+                className="euiTableRowCell__mobileHeader euiTableRowCell--hideForDesktop"
+              >
+                Type
+              </div>
+              <div
+                className="euiTableCellContent euiTableCellContent--overflowingContent"
+              >
+                <Styled(ErrorOverviewLink)
+                  className=""
+                  query={
+                    Object {
+                      "end": "2018-01-10T10:06:41.050Z",
+                      "kuery": "error.exception.type:undefined",
+                      "page": 0,
+                      "serviceName": "opbeans-python",
+                      "start": "2018-01-10T09:51:41.050Z",
+                      "transactionType": "request",
+                    }
+                  }
+                  serviceName="opbeans-python"
+                >
+                  <EuiLink
+                    className="c1"
+                    href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                  >
+                    <a
+                      className="euiLink euiLink--primary c1"
+                      href="#/services/opbeans-python/errors?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0&page=0&serviceName=opbeans-python&transactionType=request&start=2018-01-10T09:51:41.050Z&end=2018-01-10T10:06:41.050Z&kuery=error.exception.type:undefined"
+                      rel="noreferrer"
+                    />
+                  </EuiLink>
+                </Styled(ErrorOverviewLink)>
+              </div>
+            </td>
             <td
               className="euiTableRowCell"
               style={
@@ -1172,7 +1405,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                   className=""
                 >
                   <div
-                    className="c1"
+                    className="c2"
                   >
                     <span
                       className="euiToolTipAnchor"
@@ -1186,13 +1419,13 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         serviceName="opbeans-python"
                       >
                         <EuiLink
-                          className="c2"
+                          className="c3"
                           href="#/services/opbeans-python/errors/8673d8bf7a032e387c101bafbab0d2bc?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
                           <a
-                            className="euiLink euiLink--primary c2"
+                            className="euiLink euiLink--primary c3"
                             href="#/services/opbeans-python/errors/8673d8bf7a032e387c101bafbab0d2bc?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0"
                             onBlur={[Function]}
                             onFocus={[Function]}
@@ -1214,7 +1447,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
                         onFocus={[Function]}
                       >
                         <div
-                          className="c3"
+                          className="c4"
                           onBlur={[Function]}
                           onFocus={[Function]}
                         >
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx
index b26833c02fe22..250b9a5d188d0 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx
@@ -23,6 +23,8 @@ import { useUrlParams } from '../../../../hooks/useUrlParams';
 import { ManagedTable } from '../../../shared/ManagedTable';
 import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink';
 import { TimestampTooltip } from '../../../shared/TimestampTooltip';
+import { ErrorOverviewLink } from '../../../shared/Links/apm/ErrorOverviewLink';
+import { APMQueryParams } from '../../../shared/Links/url_helpers';
 
 const GroupIdLink = styled(ErrorDetailLink)`
   font-family: ${fontFamilyCode};
@@ -32,6 +34,10 @@ const MessageAndCulpritCell = styled.div`
   ${truncate('100%')};
 `;
 
+const ErrorLink = styled(ErrorOverviewLink)`
+  ${truncate('100%')};
+`;
+
 const MessageLink = styled(ErrorDetailLink)`
   font-family: ${fontFamilyCode};
   font-size: ${fontSizes.large};
@@ -48,9 +54,8 @@ interface Props {
 
 const ErrorGroupList: React.FC<Props> = props => {
   const { items } = props;
-  const {
-    urlParams: { serviceName }
-  } = useUrlParams();
+  const { urlParams } = useUrlParams();
+  const { serviceName } = urlParams;
 
   if (!serviceName) {
     throw new Error('Service name is required');
@@ -73,6 +78,29 @@ const ErrorGroupList: React.FC<Props> = props => {
           );
         }
       },
+      {
+        name: i18n.translate('xpack.apm.errorsTable.typeColumnLabel', {
+          defaultMessage: 'Type'
+        }),
+        field: 'type',
+        sortable: false,
+        render: (type: string, item: ErrorGroupListAPIResponse[0]) => {
+          return (
+            <ErrorLink
+              title={type}
+              serviceName={serviceName}
+              query={
+                {
+                  ...urlParams,
+                  kuery: `error.exception.type:${type}`
+                } as APMQueryParams
+              }
+            >
+              {type}
+            </ErrorLink>
+          );
+        }
+      },
       {
         name: i18n.translate(
           'xpack.apm.errorsTable.errorMessageAndCulpritColumnLabel',
@@ -150,7 +178,7 @@ const ErrorGroupList: React.FC<Props> = props => {
           )
       }
     ],
-    [serviceName]
+    [serviceName, urlParams]
   );
 
   return (
diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap
index 5de82a9ee8788..54dd4704edfc0 100644
--- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap
+++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap
@@ -16,6 +16,8 @@ exports[`Error ERROR_EXC_HANDLED 1`] = `undefined`;
 
 exports[`Error ERROR_EXC_MESSAGE 1`] = `undefined`;
 
+exports[`Error ERROR_EXC_TYPE 1`] = `undefined`;
+
 exports[`Error ERROR_GROUP_ID 1`] = `"grouping key"`;
 
 exports[`Error ERROR_LOG_LEVEL 1`] = `undefined`;
@@ -144,6 +146,8 @@ exports[`Span ERROR_EXC_HANDLED 1`] = `undefined`;
 
 exports[`Span ERROR_EXC_MESSAGE 1`] = `undefined`;
 
+exports[`Span ERROR_EXC_TYPE 1`] = `undefined`;
+
 exports[`Span ERROR_GROUP_ID 1`] = `undefined`;
 
 exports[`Span ERROR_LOG_LEVEL 1`] = `undefined`;
@@ -272,6 +276,8 @@ exports[`Transaction ERROR_EXC_HANDLED 1`] = `undefined`;
 
 exports[`Transaction ERROR_EXC_MESSAGE 1`] = `undefined`;
 
+exports[`Transaction ERROR_EXC_TYPE 1`] = `undefined`;
+
 exports[`Transaction ERROR_GROUP_ID 1`] = `undefined`;
 
 exports[`Transaction ERROR_LOG_LEVEL 1`] = `undefined`;
diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
index bc1b346f50da7..d5c3f91eb9247 100644
--- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
+++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
@@ -60,6 +60,7 @@ export const ERROR_LOG_LEVEL = 'error.log.level';
 export const ERROR_LOG_MESSAGE = 'error.log.message';
 export const ERROR_EXC_MESSAGE = 'error.exception.message'; // only to be used in es queries, since error.exception is now an array
 export const ERROR_EXC_HANDLED = 'error.exception.handled'; // only to be used in es queries, since error.exception is now an array
+export const ERROR_EXC_TYPE = 'error.exception.type';
 export const ERROR_PAGE_URL = 'error.page.url';
 
 // METRICS
diff --git a/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap
index b9ac9d5431700..982ad558dc91d 100644
--- a/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap
+++ b/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap
@@ -73,6 +73,7 @@ Object {
                 "error.log.message",
                 "error.exception.message",
                 "error.exception.handled",
+                "error.exception.type",
                 "error.culprit",
                 "error.grouping_key",
                 "@timestamp",
@@ -148,6 +149,7 @@ Object {
                 "error.log.message",
                 "error.exception.message",
                 "error.exception.handled",
+                "error.exception.type",
                 "error.culprit",
                 "error.grouping_key",
                 "@timestamp",
diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts
index 8ea6df5a9898a..5221d737866f4 100644
--- a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts
+++ b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts
@@ -8,6 +8,7 @@ import {
   ERROR_CULPRIT,
   ERROR_EXC_HANDLED,
   ERROR_EXC_MESSAGE,
+  ERROR_EXC_TYPE,
   ERROR_GROUP_ID,
   ERROR_LOG_MESSAGE
 } from '../../../common/elasticsearch_fieldnames';
@@ -67,6 +68,7 @@ export async function getErrorGroups({
                   ERROR_LOG_MESSAGE,
                   ERROR_EXC_MESSAGE,
                   ERROR_EXC_HANDLED,
+                  ERROR_EXC_TYPE,
                   ERROR_CULPRIT,
                   ERROR_GROUP_ID,
                   '@timestamp'
@@ -99,6 +101,7 @@ export async function getErrorGroups({
       exception?: Array<{
         handled?: boolean;
         message?: string;
+        type?: string;
       }>;
       culprit: APMError['error']['culprit'];
       grouping_key: APMError['error']['grouping_key'];
@@ -120,7 +123,8 @@ export async function getErrorGroups({
       culprit: source.error.culprit,
       groupId: source.error.grouping_key,
       latestOccurrenceAt: source['@timestamp'],
-      handled: source.error.exception?.[0].handled
+      handled: source.error.exception?.[0].handled,
+      type: source.error.exception?.[0].type
     };
   });
 

From c643148f3613df41565a25e49b0f8c88fb17876a Mon Sep 17 00:00:00 2001
From: Frank Hassanabad <frank.hassanabad@elastic.co>
Date: Wed, 8 Apr 2020 17:36:20 -0600
Subject: [PATCH 08/78] [SIEM][Detection Engine] Fix rule notification critical
 bugs

## Summary

Fixes critical bugs found during testing of the rule notification.

* Fixes a bug where when you turn on rules quickly such as ML rules you would see these message below. This message can also be seen when you first create a rule with an action notification. This is a race condition with how we update rules multiple times when we really should only update it once and do it before enabling a rule

```
server    log   [12:18:35.986] [error][alerting][alerting][plugins][plugins] Executing Alert "63b828b5-24b9-4d55-83ee-8a8201fe2d76" has resulted in Error: [security_exception] missing authentication credentials for REST request [/_security/user/_has_privileges], with { header={ WWW-Authenticate={ 0="Bearer realm=\"security\"" & 1="ApiKey" & 2="Basic realm=\"security\" charset=\"UTF-8\"" } }
```

* Fixes a bug where we were using `ruleParams.interval` when we should have been using `ruleAlertSavedObject.attributes.schedule.interval`. When changing rule notifications to run daily, weekly, etc.. you would see this exception being thrown:

```
server    log   [21:23:08.028] [error][alerting][alerting][plugins][plugins] Executing Alert "fedcccc0-7c69-4e2f-83f8-d8ee88ab5484" has resulted in Error: "from" or "to" was not provided to signals count query
```

* Fixes misc typing issues found
* Fixes it to where we no longer make multiple DB calls but rather pass down objects we already have.
* Changes the work flow to where we only update, create, or patch the alerting object once which fixes the race condition and improves the backend performance.
* Removes left over unused code
* Applied https://en.wikipedia.org/wiki/Single-entry_single-exit to functions where it made sense and easier to read.


### Checklist

- [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
---
 .../legacy/plugins/siem/common/constants.ts   |  2 -
 .../notifications/add_tags.ts                 |  2 +-
 .../create_notifications.test.ts              |  2 -
 .../notifications/create_notifications.ts     |  5 +-
 .../rules_notification_alert_type.ts          |  4 +-
 .../detection_engine/notifications/types.ts   |  9 ++--
 .../update_notifications.test.ts              |  9 +---
 .../notifications/update_notifications.ts     | 27 ++++------
 .../routes/rules/create_rules_bulk_route.ts   |  1 +
 .../routes/rules/create_rules_route.ts        |  1 +
 .../routes/rules/import_rules_route.ts        |  1 +
 .../routes/rules/update_rules_bulk_route.ts   |  1 +
 .../routes/rules/update_rules_route.ts        |  1 +
 .../create_rule_actions_saved_object.ts       |  8 +--
 .../delete_rule_actions_saved_object.ts       |  9 ++--
 .../get_rule_actions_saved_object.ts          | 16 +++---
 ...ate_or_create_rule_actions_saved_object.ts | 11 ++--
 .../update_rule_actions_saved_object.ts       | 15 ++----
 .../rules/create_rules.test.ts                |  1 +
 .../detection_engine/rules/create_rules.ts    |  4 +-
 .../rules/install_prepacked_rules.ts          |  1 +
 .../lib/detection_engine/rules/patch_rules.ts |  2 +-
 .../lib/detection_engine/rules/types.ts       |  6 +--
 .../rules/update_rule_actions.ts              | 54 -------------------
 .../rules/update_rules.test.ts                |  3 ++
 .../detection_engine/rules/update_rules.ts    |  6 ++-
 .../rules/update_rules_notifications.ts       |  9 +---
 .../lib/detection_engine/signals/types.ts     |  7 ++-
 28 files changed, 75 insertions(+), 142 deletions(-)
 delete mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rule_actions.ts

diff --git a/x-pack/legacy/plugins/siem/common/constants.ts b/x-pack/legacy/plugins/siem/common/constants.ts
index 662fb8fb8ef68..22f1b3beffa35 100644
--- a/x-pack/legacy/plugins/siem/common/constants.ts
+++ b/x-pack/legacy/plugins/siem/common/constants.ts
@@ -65,8 +65,6 @@ export const INTERNAL_IDENTIFIER = '__internal';
 export const INTERNAL_RULE_ID_KEY = `${INTERNAL_IDENTIFIER}_rule_id`;
 export const INTERNAL_RULE_ALERT_ID_KEY = `${INTERNAL_IDENTIFIER}_rule_alert_id`;
 export const INTERNAL_IMMUTABLE_KEY = `${INTERNAL_IDENTIFIER}_immutable`;
-export const INTERNAL_NOTIFICATION_ID_KEY = `${INTERNAL_IDENTIFIER}_notification_id`;
-export const INTERNAL_NOTIFICATION_RULE_ID_KEY = `${INTERNAL_IDENTIFIER}_notification_rule_id`;
 
 /**
  * Detection engine routes
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/add_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/add_tags.ts
index 6955e57d099be..14b2e1ae9e366 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/add_tags.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/add_tags.ts
@@ -6,5 +6,5 @@
 
 import { INTERNAL_RULE_ALERT_ID_KEY } from '../../../../common/constants';
 
-export const addTags = (tags: string[] = [], ruleAlertId: string): string[] =>
+export const addTags = (tags: string[], ruleAlertId: string): string[] =>
   Array.from(new Set([...tags, `${INTERNAL_RULE_ALERT_ID_KEY}:${ruleAlertId}`]));
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.test.ts
index 073251b68f414..3878f5dae8889 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.test.ts
@@ -24,7 +24,6 @@ describe('createNotifications', () => {
       enabled: true,
       interval: '',
       name: '',
-      tags: [],
     });
 
     expect(alertsClient.create).toHaveBeenCalledWith(
@@ -52,7 +51,6 @@ describe('createNotifications', () => {
       enabled: true,
       interval: '',
       name: '',
-      tags: [],
     });
 
     expect(alertsClient.create).toHaveBeenCalledWith(
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.ts
index 3a1697f1c8afc..ccd7576255d83 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/create_notifications.ts
@@ -17,12 +17,11 @@ export const createNotifications = async ({
   ruleAlertId,
   interval,
   name,
-  tags,
 }: CreateNotificationParams): Promise<Alert> =>
   alertsClient.create({
     data: {
       name,
-      tags: addTags(tags, ruleAlertId),
+      tags: addTags([], ruleAlertId),
       alertTypeId: NOTIFICATIONS_ID,
       consumer: APP_ID,
       params: {
@@ -30,7 +29,7 @@ export const createNotifications = async ({
       },
       schedule: { interval },
       enabled,
-      actions: actions?.map(transformRuleToAlertAction),
+      actions: actions.map(transformRuleToAlertAction),
       throttle: null,
     },
   });
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/rules_notification_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/rules_notification_alert_type.ts
index ced81098c9f8e..e4ad53de742d6 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/rules_notification_alert_type.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/rules_notification_alert_type.ts
@@ -45,7 +45,9 @@ export const rulesNotificationAlertType = ({
     const ruleParams = { ...ruleAlertParams, name: ruleName, id: ruleAlertSavedObject.id };
 
     const fromInMs = parseScheduleDates(
-      previousStartedAt ? previousStartedAt.toISOString() : `now-${ruleParams.interval}`
+      previousStartedAt
+        ? previousStartedAt.toISOString()
+        : `now-${ruleAlertSavedObject.attributes.schedule.interval}`
     )?.format('x');
     const toInMs = parseScheduleDates(startedAt.toISOString())?.format('x');
 
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/types.ts
index 128a7965cd7dc..32a8737adc7c9 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/types.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/types.ts
@@ -45,10 +45,11 @@ export interface Clients {
   alertsClient: AlertsClient;
 }
 
-export type UpdateNotificationParams = Omit<NotificationAlertParams, 'interval' | 'actions'> & {
+export type UpdateNotificationParams = Omit<
+  NotificationAlertParams,
+  'interval' | 'actions' | 'tags'
+> & {
   actions: RuleAlertAction[];
-  id?: string;
-  tags?: string[];
   interval: string | null | undefined;
   ruleAlertId: string;
 } & Clients;
@@ -64,8 +65,6 @@ export interface NotificationAlertParams {
   ruleAlertId: string;
   interval: string;
   name: string;
-  tags?: string[];
-  throttle?: null;
 }
 
 export type CreateNotificationParams = NotificationAlertParams & Clients;
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.test.ts
index 4c077dd9fc1fb..e1f7526438c31 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.test.ts
@@ -9,6 +9,7 @@ import { updateNotifications } from './update_notifications';
 import { readNotifications } from './read_notifications';
 import { createNotifications } from './create_notifications';
 import { getNotificationResult } from '../routes/__mocks__/request_responses';
+import { UpdateNotificationParams } from './types';
 jest.mock('./read_notifications');
 jest.mock('./create_notifications');
 
@@ -30,7 +31,6 @@ describe('updateNotifications', () => {
       enabled: true,
       interval: '10m',
       name: '',
-      tags: [],
     });
 
     expect(alertsClient.update).toHaveBeenCalledWith(
@@ -48,14 +48,13 @@ describe('updateNotifications', () => {
   it('should create a new notification if did not exist', async () => {
     (readNotifications as jest.Mock).mockResolvedValue(null);
 
-    const params = {
+    const params: UpdateNotificationParams = {
       alertsClient,
       actions: [],
       ruleAlertId: 'new-rule-id',
       enabled: true,
       interval: '10m',
       name: '',
-      tags: [],
     };
 
     await updateNotifications(params);
@@ -73,7 +72,6 @@ describe('updateNotifications', () => {
       enabled: true,
       interval: null,
       name: '',
-      tags: [],
     });
 
     expect(alertsClient.delete).toHaveBeenCalledWith(
@@ -98,7 +96,6 @@ describe('updateNotifications', () => {
       enabled: true,
       interval: '10m',
       name: '',
-      tags: [],
     });
 
     expect(alertsClient.update).toHaveBeenCalledWith(
@@ -125,10 +122,8 @@ describe('updateNotifications', () => {
       alertsClient,
       actions: [],
       enabled: true,
-      id: notification.id,
       ruleAlertId,
       name: notification.name,
-      tags: notification.tags,
       interval: null,
     });
 
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.ts
index 3197d21c0e95a..ac0de406aceb2 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/notifications/update_notifications.ts
@@ -15,50 +15,41 @@ export const updateNotifications = async ({
   alertsClient,
   actions,
   enabled,
-  id,
   ruleAlertId,
   name,
-  tags,
   interval,
 }: UpdateNotificationParams): Promise<PartialAlert | null> => {
-  const notification = await readNotifications({ alertsClient, id, ruleAlertId });
+  const notification = await readNotifications({ alertsClient, id: undefined, ruleAlertId });
 
   if (interval && notification) {
-    const result = await alertsClient.update({
+    return alertsClient.update({
       id: notification.id,
       data: {
-        tags: addTags(tags, ruleAlertId),
+        tags: addTags([], ruleAlertId),
         name,
         schedule: {
           interval,
         },
-        actions: actions?.map(transformRuleToAlertAction),
+        actions: actions.map(transformRuleToAlertAction),
         params: {
           ruleAlertId,
         },
         throttle: null,
       },
     });
-    return result;
-  }
-
-  if (interval && !notification) {
-    const result = await createNotifications({
+  } else if (interval && !notification) {
+    return createNotifications({
       alertsClient,
       enabled,
-      tags,
       name,
       interval,
       actions,
       ruleAlertId,
     });
-    return result;
-  }
-
-  if (!interval && notification) {
+  } else if (!interval && notification) {
     await alertsClient.delete({ id: notification.id });
     return null;
+  } else {
+    return null;
   }
-
-  return null;
 };
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts
index d0e36515946a8..5377e9039785e 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts
@@ -144,6 +144,7 @@ export const createRulesBulkRoute = (router: IRouter) => {
                 note,
                 version,
                 lists,
+                actions: throttle === 'rule' ? actions : [], // Only enable actions if throttle is set to rule, otherwise we are a notification and should not enable it,
               });
 
               const ruleActions = await updateRulesNotifications({
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
index 6038ad2095323..9a329b78b8f12 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
@@ -132,6 +132,7 @@ export const createRulesRoute = (router: IRouter): void => {
           note,
           version: 1,
           lists,
+          actions: throttle === 'rule' ? actions : [], // Only enable actions if throttle is rule, otherwise we are a notification and should not enable it,
         });
 
         const ruleActions = await updateRulesNotifications({
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts
index 43e970702ba72..29ae5056a3ae8 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts
@@ -196,6 +196,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config
                         note,
                         version,
                         lists,
+                        actions: [], // Actions are not imported nor exported at this time
                       });
                       resolve({ rule_id: ruleId, status_code: 200 });
                     } else if (rule != null && request.query.overwrite) {
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts
index 9916972f41843..36e15780f5cb3 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts
@@ -122,6 +122,7 @@ export const updateRulesBulkRoute = (router: IRouter) => {
               note,
               version,
               lists,
+              actions,
             });
             if (rule != null) {
               const ruleActions = await updateRulesNotifications({
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
index 21dd2a4429cca..0444c757a9b31 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
@@ -118,6 +118,7 @@ export const updateRulesRoute = (router: IRouter) => {
           note,
           version,
           lists,
+          actions: throttle === 'rule' ? actions : [], // Only enable actions if throttle is rule, otherwise we are a notification and should not enable it
         });
 
         if (rule != null) {
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/create_rule_actions_saved_object.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/create_rule_actions_saved_object.ts
index 97cfc1d2d9ea7..991690d901d8a 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/create_rule_actions_saved_object.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/create_rule_actions_saved_object.ts
@@ -9,6 +9,7 @@ import { AlertServices } from '../../../../../../../plugins/alerting/server';
 import { ruleActionsSavedObjectType } from './saved_object_mappings';
 import { IRuleActionsAttributesSavedObjectAttributes } from './types';
 import { getThrottleOptions, getRuleActionsFromSavedObject } from './utils';
+import { RulesActionsSavedObject } from './get_rule_actions_saved_object';
 
 interface CreateRuleActionsSavedObject {
   ruleAlertId: string;
@@ -22,12 +23,7 @@ export const createRuleActionsSavedObject = async ({
   savedObjectsClient,
   actions = [],
   throttle,
-}: CreateRuleActionsSavedObject): Promise<{
-  id: string;
-  actions: RuleAlertAction[];
-  alertThrottle: string | null;
-  ruleThrottle: string;
-}> => {
+}: CreateRuleActionsSavedObject): Promise<RulesActionsSavedObject> => {
   const ruleActionsSavedObject = await savedObjectsClient.create<
     IRuleActionsAttributesSavedObjectAttributes
   >(ruleActionsSavedObjectType, {
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/delete_rule_actions_saved_object.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/delete_rule_actions_saved_object.ts
index 864281da5bafd..91489334940bd 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/delete_rule_actions_saved_object.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/delete_rule_actions_saved_object.ts
@@ -18,8 +18,9 @@ export const deleteRuleActionsSavedObject = async ({
   savedObjectsClient,
 }: DeleteRuleActionsSavedObject): Promise<{} | null> => {
   const ruleActions = await getRuleActionsSavedObject({ ruleAlertId, savedObjectsClient });
-
-  if (!ruleActions) return null;
-
-  return savedObjectsClient.delete(ruleActionsSavedObjectType, ruleActions.id);
+  if (ruleActions != null) {
+    return savedObjectsClient.delete(ruleActionsSavedObjectType, ruleActions.id);
+  } else {
+    return null;
+  }
 };
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/get_rule_actions_saved_object.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/get_rule_actions_saved_object.ts
index 61b544db5a18a..dad35f6cb1f96 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/get_rule_actions_saved_object.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/get_rule_actions_saved_object.ts
@@ -15,15 +15,17 @@ interface GetRuleActionsSavedObject {
   savedObjectsClient: AlertServices['savedObjectsClient'];
 }
 
-export const getRuleActionsSavedObject = async ({
-  ruleAlertId,
-  savedObjectsClient,
-}: GetRuleActionsSavedObject): Promise<{
+export interface RulesActionsSavedObject {
   id: string;
   actions: RuleAlertAction[];
   alertThrottle: string | null;
   ruleThrottle: string;
-} | null> => {
+}
+
+export const getRuleActionsSavedObject = async ({
+  ruleAlertId,
+  savedObjectsClient,
+}: GetRuleActionsSavedObject): Promise<RulesActionsSavedObject | null> => {
   const { saved_objects } = await savedObjectsClient.find<
     IRuleActionsAttributesSavedObjectAttributes
   >({
@@ -35,7 +37,7 @@ export const getRuleActionsSavedObject = async ({
 
   if (!saved_objects[0]) {
     return null;
+  } else {
+    return getRuleActionsFromSavedObject(saved_objects[0]);
   }
-
-  return getRuleActionsFromSavedObject(saved_objects[0]);
 };
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_or_create_rule_actions_saved_object.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_or_create_rule_actions_saved_object.ts
index adc87150f89a7..d79c61f6200e3 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_or_create_rule_actions_saved_object.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_or_create_rule_actions_saved_object.ts
@@ -24,16 +24,17 @@ export const updateOrCreateRuleActionsSavedObject = async ({
   actions,
   throttle,
 }: UpdateOrCreateRuleActionsSavedObject): Promise<RuleActions> => {
-  const currentRuleActions = await getRuleActionsSavedObject({ ruleAlertId, savedObjectsClient });
+  const ruleActions = await getRuleActionsSavedObject({ ruleAlertId, savedObjectsClient });
 
-  if (currentRuleActions) {
+  if (ruleActions != null) {
     return updateRuleActionsSavedObject({
       ruleAlertId,
       savedObjectsClient,
       actions,
       throttle,
-    }) as Promise<RuleActions>;
+      ruleActions,
+    });
+  } else {
+    return createRuleActionsSavedObject({ ruleAlertId, savedObjectsClient, actions, throttle });
   }
-
-  return createRuleActionsSavedObject({ ruleAlertId, savedObjectsClient, actions, throttle });
 };
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_rule_actions_saved_object.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_rule_actions_saved_object.ts
index a15005110c56b..2a2c84838ed93 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_rule_actions_saved_object.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rule_actions/update_rule_actions_saved_object.ts
@@ -6,7 +6,7 @@
 
 import { AlertServices } from '../../../../../../../plugins/alerting/server';
 import { ruleActionsSavedObjectType } from './saved_object_mappings';
-import { getRuleActionsSavedObject } from './get_rule_actions_saved_object';
+import { RulesActionsSavedObject } from './get_rule_actions_saved_object';
 import { RuleAlertAction } from '../../../../common/detection_engine/types';
 import { getThrottleOptions } from './utils';
 import { IRuleActionsAttributesSavedObjectAttributes } from './types';
@@ -16,6 +16,7 @@ interface DeleteRuleActionsSavedObject {
   savedObjectsClient: AlertServices['savedObjectsClient'];
   actions: RuleAlertAction[] | undefined;
   throttle: string | null | undefined;
+  ruleActions: RulesActionsSavedObject;
 }
 
 export const updateRuleActionsSavedObject = async ({
@@ -23,16 +24,8 @@ export const updateRuleActionsSavedObject = async ({
   savedObjectsClient,
   actions,
   throttle,
-}: DeleteRuleActionsSavedObject): Promise<{
-  ruleThrottle: string;
-  alertThrottle: string | null;
-  actions: RuleAlertAction[];
-  id: string;
-} | null> => {
-  const ruleActions = await getRuleActionsSavedObject({ ruleAlertId, savedObjectsClient });
-
-  if (!ruleActions) return null;
-
+  ruleActions,
+}: DeleteRuleActionsSavedObject): Promise<RulesActionsSavedObject> => {
   const throttleOptions = throttle
     ? getThrottleOptions(throttle)
     : {
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts
index 4c8d0f51f251b..a60f1d4177978 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts
@@ -34,6 +34,7 @@ describe('createRules', () => {
       interval: '',
       name: '',
       tags: [],
+      actions: [],
     });
 
     expect(alertsClient.create).toHaveBeenCalledWith(
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts
index bebf4f350483b..91effb4741b8b 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts
@@ -4,6 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions';
 import { Alert } from '../../../../../../../plugins/alerting/common';
 import { APP_ID, SIGNALS_ID } from '../../../../common/constants';
 import { CreateRuleParams } from './types';
@@ -42,6 +43,7 @@ export const createRules = async ({
   note,
   version,
   lists,
+  actions,
 }: CreateRuleParams): Promise<Alert> => {
   // TODO: Remove this and use regular lists once the feature is stable for a release
   const listsParam = hasListsFeature() ? { lists } : {};
@@ -81,7 +83,7 @@ export const createRules = async ({
       },
       schedule: { interval },
       enabled,
-      actions: [],
+      actions: actions.map(transformRuleToAlertAction),
       throttle: null,
     },
   });
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts
index bcbe460fb6a66..6d4bacb9cc243 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts
@@ -83,6 +83,7 @@ export const installPrepackagedRules = (
         note,
         version,
         lists,
+        actions: [], // At this time there is no pre-packaged actions
       }),
     ];
   }, []);
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts
index d7655a15499eb..5c4889ec5fd68 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts
@@ -120,7 +120,7 @@ export const patchRules = async ({
     id: rule.id,
     data: {
       tags: addTags(tags ?? rule.tags, rule.params.ruleId, immutable ?? rule.params.immutable),
-      throttle: rule.throttle,
+      throttle: null,
       name: calculateName({ updatedName: name, originalName: rule.name }),
       schedule: {
         interval: calculateInterval(interval, rule.schedule.interval),
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts
index 38b1097a845f8..b1bed5d716155 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts
@@ -142,12 +142,12 @@ export interface Clients {
   actionsClient: ActionsClient;
 }
 
-export type PatchRuleParams = Partial<Omit<RuleAlertParams, 'actions' | 'throttle'>> & {
+export type PatchRuleParams = Partial<Omit<RuleAlertParams, 'throttle'>> & {
   id: string | undefined | null;
   savedObjectsClient: SavedObjectsClientContract;
 } & Clients;
 
-export type UpdateRuleParams = Omit<RuleAlertParams, 'immutable' | 'actions' | 'throttle'> & {
+export type UpdateRuleParams = Omit<RuleAlertParams, 'immutable' | 'throttle'> & {
   id: string | undefined | null;
   savedObjectsClient: SavedObjectsClientContract;
 } & Clients;
@@ -157,7 +157,7 @@ export type DeleteRuleParams = Clients & {
   ruleId: string | undefined | null;
 };
 
-export type CreateRuleParams = Omit<RuleAlertParams, 'ruleId' | 'actions' | 'throttle'> & {
+export type CreateRuleParams = Omit<RuleAlertParams, 'ruleId' | 'throttle'> & {
   ruleId: string;
 } & Clients;
 
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rule_actions.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rule_actions.ts
deleted file mode 100644
index e6ee1e6a29764..0000000000000
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rule_actions.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import {
-  AlertsClient,
-  AlertServices,
-  PartialAlert,
-} from '../../../../../../../plugins/alerting/server';
-import { getRuleActionsSavedObject } from '../rule_actions/get_rule_actions_saved_object';
-import { readRules } from './read_rules';
-import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions';
-
-interface UpdateRuleActions {
-  alertsClient: AlertsClient;
-  savedObjectsClient: AlertServices['savedObjectsClient'];
-  ruleAlertId: string;
-}
-
-export const updateRuleActions = async ({
-  alertsClient,
-  savedObjectsClient,
-  ruleAlertId,
-}: UpdateRuleActions): Promise<PartialAlert | null> => {
-  const rule = await readRules({ alertsClient, id: ruleAlertId });
-  if (rule == null) {
-    return null;
-  }
-
-  const ruleActions = await getRuleActionsSavedObject({
-    savedObjectsClient,
-    ruleAlertId,
-  });
-
-  if (!ruleActions) {
-    return null;
-  }
-
-  return alertsClient.update({
-    id: ruleAlertId,
-    data: {
-      actions: !ruleActions.alertThrottle
-        ? ruleActions.actions.map(transformRuleToAlertAction)
-        : [],
-      throttle: null,
-      name: rule.name,
-      tags: rule.tags,
-      schedule: rule.schedule,
-      params: rule.params,
-    },
-  });
-};
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts
index ca299db6ace50..72f4cbcbe68e8 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts
@@ -35,6 +35,7 @@ describe('updateRules', () => {
       interval: '',
       name: '',
       tags: [],
+      actions: [],
     });
 
     expect(alertsClient.disable).toHaveBeenCalledWith(
@@ -61,6 +62,7 @@ describe('updateRules', () => {
       interval: '',
       name: '',
       tags: [],
+      actions: [],
     });
 
     expect(alertsClient.enable).toHaveBeenCalledWith(
@@ -89,6 +91,7 @@ describe('updateRules', () => {
       interval: '',
       name: '',
       tags: [],
+      actions: [],
     });
 
     expect(alertsClient.update).toHaveBeenCalledWith(
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts
index 0e70e05f4de78..99326768ed33b 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts
@@ -4,6 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions';
 import { PartialAlert } from '../../../../../../../plugins/alerting/server';
 import { readRules } from './read_rules';
 import { IRuleSavedAttributesSavedObjectAttributes, UpdateRuleParams } from './types';
@@ -46,6 +47,7 @@ export const updateRules = async ({
   lists,
   anomalyThreshold,
   machineLearningJobId,
+  actions,
 }: UpdateRuleParams): Promise<PartialAlert | null> => {
   const rule = await readRules({ alertsClient, ruleId, id });
   if (rule == null) {
@@ -90,8 +92,8 @@ export const updateRules = async ({
       tags: addTags(tags, rule.params.ruleId, rule.params.immutable),
       name,
       schedule: { interval },
-      actions: rule.actions,
-      throttle: rule.throttle,
+      actions: actions.map(transformRuleToAlertAction),
+      throttle: null,
       params: {
         description,
         ruleId: rule.params.ruleId,
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules_notifications.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules_notifications.ts
index bb66a5ee1342f..994a54048b71a 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules_notifications.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules_notifications.ts
@@ -8,7 +8,6 @@ import { RuleAlertAction } from '../../../../common/detection_engine/types';
 import { AlertsClient, AlertServices } from '../../../../../../../plugins/alerting/server';
 import { updateOrCreateRuleActionsSavedObject } from '../rule_actions/update_or_create_rule_actions_saved_object';
 import { updateNotifications } from '../notifications/update_notifications';
-import { updateRuleActions } from './update_rule_actions';
 import { RuleActions } from '../rule_actions/types';
 
 interface UpdateRulesNotifications {
@@ -37,19 +36,13 @@ export const updateRulesNotifications = async ({
     throttle,
   });
 
-  await updateRuleActions({
-    alertsClient,
-    savedObjectsClient,
-    ruleAlertId,
-  });
-
   await updateNotifications({
     alertsClient,
     ruleAlertId,
     enabled,
     name,
     actions: ruleActions.actions,
-    interval: ruleActions?.alertThrottle,
+    interval: ruleActions.alertThrottle,
   });
 
   return ruleActions;
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts
index d4469351de544..040e32aa0d360 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts
@@ -162,5 +162,10 @@ export interface AlertAttributes {
 }
 
 export interface RuleAlertAttributes extends AlertAttributes {
-  params: Omit<RuleAlertParams, 'ruleId'> & { ruleId: string };
+  params: Omit<
+    RuleAlertParams,
+    'ruleId' | 'name' | 'enabled' | 'interval' | 'tags' | 'actions' | 'throttle'
+  > & {
+    ruleId: string;
+  };
 }

From 274cb805e1ed5138b0e0cd285aa9d420be5ce2b4 Mon Sep 17 00:00:00 2001
From: "Devin W. Hurley" <devin.hurley@elastic.co>
Date: Wed, 8 Apr 2020 19:58:50 -0400
Subject: [PATCH 09/78] =?UTF-8?q?[SIEM]=20[Detection=20Engine]=20Fixes=20b?=
 =?UTF-8?q?ug=20when=20notification=20doesn't=E2=80=A6=20(#63013)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Set refresh on bulk create to 'wait_for' when actions are present, so we do not respond until the newly indexed signals are searchable.

* set refresh on bulk create to 'wait_for' when actions are present, so we do not respond until the newly indexed signals are searchable

* fix types in tests
---
 .../signals/bulk_create_ml_signals.ts         |  3 +-
 .../signals/search_after_bulk_create.test.ts  |  8 +++++
 .../signals/search_after_bulk_create.ts       |  6 +++-
 .../signals/signal_rule_alert_type.test.ts    | 32 +++++++++++++++++++
 .../signals/signal_rule_alert_type.ts         |  3 ++
 .../signals/single_bulk_create.test.ts        |  6 ++++
 .../signals/single_bulk_create.ts             |  6 ++--
 .../siem/server/lib/detection_engine/types.ts |  2 ++
 8 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts
index 355041d9efbdb..ba8938f116fc6 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts
@@ -10,7 +10,7 @@ import { SearchResponse } from 'elasticsearch';
 import { Logger } from '../../../../../../../../src/core/server';
 import { AlertServices } from '../../../../../../../plugins/alerting/server';
 import { RuleAlertAction } from '../../../../common/detection_engine/types';
-import { RuleTypeParams } from '../types';
+import { RuleTypeParams, RefreshTypes } from '../types';
 import { singleBulkCreate, SingleBulkCreateResponse } from './single_bulk_create';
 import { AnomalyResults, Anomaly } from '../../machine_learning';
 
@@ -29,6 +29,7 @@ interface BulkCreateMlSignalsParams {
   updatedBy: string;
   interval: string;
   enabled: boolean;
+  refresh: RefreshTypes;
   tags: string[];
   throttle: string;
 }
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts
index 414270ffcdd5c..81600b0b8dd9b 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts
@@ -52,6 +52,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -126,6 +127,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -156,6 +158,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -198,6 +201,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -240,6 +244,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -284,6 +289,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -328,6 +334,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -374,6 +381,7 @@ describe('searchAfterAndBulkCreate', () => {
       enabled: true,
       pageSize: 1,
       filter: undefined,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts
index ff81730bc4a72..3a964cb91fbdb 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts
@@ -6,7 +6,7 @@
 
 import { AlertServices } from '../../../../../../../plugins/alerting/server';
 import { RuleAlertAction } from '../../../../common/detection_engine/types';
-import { RuleTypeParams } from '../types';
+import { RuleTypeParams, RefreshTypes } from '../types';
 import { Logger } from '../../../../../../../../src/core/server';
 import { singleSearchAfter } from './single_search_after';
 import { singleBulkCreate } from './single_bulk_create';
@@ -30,6 +30,7 @@ interface SearchAfterAndBulkCreateParams {
   enabled: boolean;
   pageSize: number;
   filter: unknown;
+  refresh: RefreshTypes;
   tags: string[];
   throttle: string;
 }
@@ -61,6 +62,7 @@ export const searchAfterAndBulkCreate = async ({
   interval,
   enabled,
   pageSize,
+  refresh,
   tags,
   throttle,
 }: SearchAfterAndBulkCreateParams): Promise<SearchAfterAndBulkCreateReturnType> => {
@@ -92,6 +94,7 @@ export const searchAfterAndBulkCreate = async ({
     updatedBy,
     interval,
     enabled,
+    refresh,
     tags,
     throttle,
   });
@@ -179,6 +182,7 @@ export const searchAfterAndBulkCreate = async ({
         updatedBy,
         interval,
         enabled,
+        refresh,
         tags,
         throttle,
       });
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts
index 3d6f443ce60d6..03fb5832fdf42 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts
@@ -105,6 +105,7 @@ describe('rules_notification_alert_type', () => {
     };
     (ruleStatusServiceFactory as jest.Mock).mockReturnValue(ruleStatusService);
     (getGapBetweenRuns as jest.Mock).mockReturnValue(moment.duration(0));
+    (searchAfterAndBulkCreate as jest.Mock).mockClear();
     (searchAfterAndBulkCreate as jest.Mock).mockResolvedValue({
       success: true,
       searchAfterTimes: [],
@@ -149,6 +150,37 @@ describe('rules_notification_alert_type', () => {
       });
     });
 
+    it("should set refresh to 'wait_for' when actions are present", async () => {
+      const ruleAlert = getResult();
+      ruleAlert.actions = [
+        {
+          actionTypeId: '.slack',
+          params: {
+            message:
+              'Rule generated {{state.signals_count}} signals\n\n{{context.rule.name}}\n{{{context.results_link}}}',
+          },
+          group: 'default',
+          id: '99403909-ca9b-49ba-9d7a-7e5320e68d05',
+        },
+      ];
+
+      savedObjectsClient.get.mockResolvedValue({
+        id: 'id',
+        type: 'type',
+        references: [],
+        attributes: ruleAlert,
+      });
+      await alert.executor(payload);
+      expect((searchAfterAndBulkCreate as jest.Mock).mock.calls[0][0].refresh).toEqual('wait_for');
+      (searchAfterAndBulkCreate as jest.Mock).mockClear();
+    });
+
+    it('should set refresh to false when actions are not present', async () => {
+      await alert.executor(payload);
+      expect((searchAfterAndBulkCreate as jest.Mock).mock.calls[0][0].refresh).toEqual(false);
+      (searchAfterAndBulkCreate as jest.Mock).mockClear();
+    });
+
     it('should call scheduleActions if signalsCount was greater than 0 and rule has actions defined', async () => {
       const ruleAlert = getResult();
       ruleAlert.actions = [
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts
index faac4a547fc17..0357f906f8035 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts
@@ -98,6 +98,7 @@ export const signalRulesAlertType = ({
         params: ruleParams,
       } = savedObject.attributes;
       const updatedAt = savedObject.updated_at ?? '';
+      const refresh = actions.length ? 'wait_for' : false;
       const buildRuleMessage = buildRuleMessageFactory({
         id: alertId,
         ruleId,
@@ -181,6 +182,7 @@ export const signalRulesAlertType = ({
             updatedAt,
             interval,
             enabled,
+            refresh,
             tags,
           });
           result.success = success;
@@ -241,6 +243,7 @@ export const signalRulesAlertType = ({
             interval,
             enabled,
             pageSize: searchAfterSize,
+            refresh,
             tags,
             throttle,
           });
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts
index 56f061cdfa3ca..45365b446cbf0 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts
@@ -159,6 +159,7 @@ describe('singleBulkCreate', () => {
       updatedBy: 'elastic',
       interval: '5m',
       enabled: true,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -192,6 +193,7 @@ describe('singleBulkCreate', () => {
       updatedBy: 'elastic',
       interval: '5m',
       enabled: true,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -217,6 +219,7 @@ describe('singleBulkCreate', () => {
       updatedBy: 'elastic',
       interval: '5m',
       enabled: true,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -243,6 +246,7 @@ describe('singleBulkCreate', () => {
       updatedBy: 'elastic',
       interval: '5m',
       enabled: true,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -271,6 +275,7 @@ describe('singleBulkCreate', () => {
       updatedBy: 'elastic',
       interval: '5m',
       enabled: true,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
@@ -365,6 +370,7 @@ describe('singleBulkCreate', () => {
       updatedBy: 'elastic',
       interval: '5m',
       enabled: true,
+      refresh: false,
       tags: ['some fake tag 1', 'some fake tag 2'],
       throttle: 'no_actions',
     });
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts
index 6dd8823b57e4d..fc33d0e15e43f 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts
@@ -9,7 +9,7 @@ import { performance } from 'perf_hooks';
 import { AlertServices } from '../../../../../../../plugins/alerting/server';
 import { SignalSearchResponse, BulkResponse } from './types';
 import { RuleAlertAction } from '../../../../common/detection_engine/types';
-import { RuleTypeParams } from '../types';
+import { RuleTypeParams, RefreshTypes } from '../types';
 import { generateId, makeFloatString } from './utils';
 import { buildBulkBody } from './build_bulk_body';
 import { Logger } from '../../../../../../../../src/core/server';
@@ -31,6 +31,7 @@ interface SingleBulkCreateParams {
   enabled: boolean;
   tags: string[];
   throttle: string;
+  refresh: RefreshTypes;
 }
 
 /**
@@ -77,6 +78,7 @@ export const singleBulkCreate = async ({
   updatedBy,
   interval,
   enabled,
+  refresh,
   tags,
   throttle,
 }: SingleBulkCreateParams): Promise<SingleBulkCreateResponse> => {
@@ -124,7 +126,7 @@ export const singleBulkCreate = async ({
   const start = performance.now();
   const response: BulkResponse = await services.callCluster('bulk', {
     index: signalsIndex,
-    refresh: false,
+    refresh,
     body: bulkBody,
   });
   const end = performance.now();
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts
index d3fa98fd73d3a..035f1b10ff8b2 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts
@@ -149,3 +149,5 @@ export type CallWithRequest<T extends Record<string, any>, V> = (
   params: T,
   options?: CallAPIOptions
 ) => Promise<V>;
+
+export type RefreshTypes = false | 'wait_for';

From 82e048a5fb57de3afd309e301536a90971edd7de Mon Sep 17 00:00:00 2001
From: Joe Reuter <johannes.reuter@elastic.co>
Date: Thu, 9 Apr 2020 09:28:44 +0200
Subject: [PATCH 10/78] add embed flag to saved object url as well (#62926)

---
 src/plugins/share/public/components/url_panel_content.tsx | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/plugins/share/public/components/url_panel_content.tsx b/src/plugins/share/public/components/url_panel_content.tsx
index 2b77b6f4592a8..2b1159be89003 100644
--- a/src/plugins/share/public/components/url_panel_content.tsx
+++ b/src/plugins/share/public/components/url_panel_content.tsx
@@ -166,7 +166,7 @@ export class UrlPanelContent extends Component<Props, State> {
     // Get the application route, after the hash, and remove the #.
     const parsedAppUrl = parseUrl(parsedUrl.hash.slice(1), true);
 
-    return formatUrl({
+    let formattedUrl = formatUrl({
       protocol: parsedUrl.protocol,
       auth: parsedUrl.auth,
       host: parsedUrl.host,
@@ -180,6 +180,11 @@ export class UrlPanelContent extends Component<Props, State> {
         },
       }),
     });
+    if (this.props.isEmbedded) {
+      formattedUrl = this.makeUrlEmbeddable(url);
+    }
+
+    return formattedUrl;
   };
 
   private getSnapshotUrl = () => {

From 7b0e9d00aafa995c4a6261be7a1446362647e170 Mon Sep 17 00:00:00 2001
From: Robert Oskamp <robert.oskamp@elastic.co>
Date: Thu, 9 Apr 2020 11:43:51 +0200
Subject: [PATCH 11/78] [ML] Functional transform tests - stabilize source
 selection (#63087)

This PR adds a retry to the transform source selection service method for functional tests.
---
 .../functional/services/transform_ui/source_selection.ts   | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/x-pack/test/functional/services/transform_ui/source_selection.ts b/x-pack/test/functional/services/transform_ui/source_selection.ts
index d2ef2c67f0004..38a819e285d67 100644
--- a/x-pack/test/functional/services/transform_ui/source_selection.ts
+++ b/x-pack/test/functional/services/transform_ui/source_selection.ts
@@ -8,6 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
 
 export function TransformSourceSelectionProvider({ getService }: FtrProviderContext) {
   const testSubjects = getService('testSubjects');
+  const retry = getService('retry');
 
   return {
     async assertSourceListContainsEntry(sourceName: string) {
@@ -23,8 +24,10 @@ export function TransformSourceSelectionProvider({ getService }: FtrProviderCont
 
     async selectSource(sourceName: string) {
       await this.filterSourceSelection(sourceName);
-      await testSubjects.clickWhenNotDisabled(`savedObjectTitle${sourceName}`);
-      await testSubjects.existOrFail('transformPageCreateTransform');
+      await retry.tryForTime(30 * 1000, async () => {
+        await testSubjects.clickWhenNotDisabled(`savedObjectTitle${sourceName}`);
+        await testSubjects.existOrFail('transformPageCreateTransform', { timeout: 10 * 1000 });
+      });
     },
   };
 }

From 7ec635798cd2b7d659fc8a247c1e8f96a2cec678 Mon Sep 17 00:00:00 2001
From: Uladzislau Lasitsa <Uladzislau_Lasitsa@epam.com>
Date: Thu, 9 Apr 2020 13:39:14 +0300
Subject: [PATCH 12/78] [data.search.aggs]: Clean up TimeBuckets implementation
 (#62123)

* Created tests for time_buckets. Clean up code. Removed getConfig method.

* Fixed comments

* Fixed comments (2)

* Fixes

* Removed __cached__

* Fixes for comments

* some refactoring

* Fixed comment about config

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../search/aggs/buckets/date_histogram.ts     |  29 ++--
 .../lib/time_buckets/time_buckets.test.ts     | 121 +++++++++++++
 .../buckets/lib/time_buckets/time_buckets.ts  | 161 +++---------------
 .../utils/calculate_auto_time_expression.ts   |  13 +-
 .../public/legacy/build_pipeline.ts           |   7 +-
 5 files changed, 178 insertions(+), 153 deletions(-)
 create mode 100644 src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts

diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts
index e6fd259fabc92..57f3aa85ad944 100644
--- a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts
+++ b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts
@@ -44,20 +44,15 @@ const updateTimeBuckets = (
   timefilter: TimefilterContract,
   customBuckets?: IBucketDateHistogramAggConfig['buckets']
 ) => {
-  const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null;
+  const bounds =
+    agg.params.timeRange && agg.fieldIsTimeField()
+      ? timefilter.calculateBounds(agg.params.timeRange)
+      : undefined;
   const buckets = customBuckets || agg.buckets;
-  buckets.setBounds(agg.fieldIsTimeField() && bounds);
+  buckets.setBounds(bounds);
   buckets.setInterval(agg.params.interval);
 };
 
-// TODO: Need to incorporate these properly into TimeBuckets
-interface ITimeBuckets {
-  setBounds: Function;
-  getScaledDateFormat: TimeBuckets['getScaledDateFormat'];
-  setInterval: Function;
-  getInterval: Function;
-}
-
 export interface DateHistogramBucketAggDependencies {
   uiSettings: IUiSettingsClient;
   query: QuerySetup;
@@ -65,7 +60,7 @@ export interface DateHistogramBucketAggDependencies {
 }
 
 export interface IBucketDateHistogramAggConfig extends IBucketAggConfig {
-  buckets: ITimeBuckets;
+  buckets: TimeBuckets;
 }
 
 export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig {
@@ -113,7 +108,12 @@ export const getDateHistogramBucketAgg = ({
               if (buckets) return buckets;
 
               const { timefilter } = query.timefilter;
-              buckets = new TimeBuckets({ uiSettings });
+              buckets = new TimeBuckets({
+                'histogram:maxBars': uiSettings.get('histogram:maxBars'),
+                'histogram:barTarget': uiSettings.get('histogram:barTarget'),
+                dateFormat: uiSettings.get('dateFormat'),
+                'dateFormat:scaled': uiSettings.get('dateFormat:scaled'),
+              });
               updateTimeBuckets(this, timefilter, buckets);
 
               return buckets;
@@ -206,7 +206,8 @@ export const getDateHistogramBucketAgg = ({
               ...dateHistogramInterval(interval.expression),
             };
 
-            const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1;
+            const scaleMetrics =
+              scaleMetricValues && interval.scaled && interval.scale && interval.scale < 1;
             if (scaleMetrics && aggs) {
               const metrics = aggs.aggs.filter(a => isMetricAggType(a.type));
               const all = every(metrics, (a: IBucketAggConfig) => {
@@ -218,7 +219,7 @@ export const getDateHistogramBucketAgg = ({
               });
               if (all) {
                 output.metricScale = interval.scale;
-                output.metricScaleText = interval.preScaled.description;
+                output.metricScaleText = interval.preScaled?.description || '';
               }
             }
           },
diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts
new file mode 100644
index 0000000000000..af3c15167295c
--- /dev/null
+++ b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts
@@ -0,0 +1,121 @@
+/*
+ * 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 moment from 'moment';
+
+import { TimeBuckets, TimeBucketsConfig } from './time_buckets';
+
+describe('TimeBuckets', () => {
+  const timeBucketConfig: TimeBucketsConfig = {
+    'histogram:maxBars': 4,
+    'histogram:barTarget': 3,
+    dateFormat: 'YYYY-MM-DD',
+    'dateFormat:scaled': [
+      ['', 'HH:mm:ss.SSS'],
+      ['PT1S', 'HH:mm:ss'],
+      ['PT1M', 'HH:mm'],
+      ['PT1H', 'YYYY-MM-DD HH:mm'],
+      ['P1DT', 'YYYY-MM-DD'],
+      ['P1YT', 'YYYY'],
+    ],
+  };
+
+  test('setBounds/getBounds - bounds is correct', () => {
+    const timeBuckets = new TimeBuckets(timeBucketConfig);
+    const bounds = {
+      min: moment('2020-03-25'),
+      max: moment('2020-03-31'),
+    };
+    timeBuckets.setBounds(bounds);
+    const timeBucketsBounds = timeBuckets.getBounds();
+
+    expect(timeBucketsBounds).toEqual(bounds);
+  });
+
+  test('setBounds/getBounds - bounds is undefined', () => {
+    const timeBuckets = new TimeBuckets(timeBucketConfig);
+    const bounds = {
+      min: moment('2020-03-25'),
+      max: moment('2020-03-31'),
+    };
+    timeBuckets.setBounds(bounds);
+    let timeBucketsBounds = timeBuckets.getBounds();
+
+    expect(timeBucketsBounds).toEqual(bounds);
+
+    timeBuckets.setBounds();
+    timeBucketsBounds = timeBuckets.getBounds();
+
+    expect(timeBucketsBounds).toBeUndefined();
+  });
+
+  test('setInterval/getInterval - intreval is a string', () => {
+    const timeBuckets = new TimeBuckets(timeBucketConfig);
+    timeBuckets.setInterval('20m');
+    const interval = timeBuckets.getInterval();
+
+    expect(interval.description).toEqual('20 minutes');
+    expect(interval.esValue).toEqual(20);
+    expect(interval.esUnit).toEqual('m');
+    expect(interval.expression).toEqual('20m');
+  });
+
+  test('setInterval/getInterval - intreval is a string and bounds is defined', () => {
+    const timeBuckets = new TimeBuckets(timeBucketConfig);
+    const bounds = {
+      min: moment('2020-03-25'),
+      max: moment('2020-03-31'),
+    };
+    timeBuckets.setBounds(bounds);
+    timeBuckets.setInterval('20m');
+    const interval = timeBuckets.getInterval();
+
+    expect(interval.description).toEqual('day');
+    expect(interval.esValue).toEqual(1);
+    expect(interval.esUnit).toEqual('d');
+    expect(interval.expression).toEqual('1d');
+    expect(interval.scaled).toBeTruthy();
+    expect(interval.scale).toEqual(0.013888888888888888);
+
+    if (interval.preScaled) {
+      expect(interval.preScaled.description).toEqual('20 minutes');
+      expect(interval.preScaled.esValue).toEqual(20);
+      expect(interval.preScaled.esUnit).toEqual('m');
+      expect(interval.preScaled.expression).toEqual('20m');
+    }
+  });
+
+  test('setInterval/getInterval - intreval is a "auto"', () => {
+    const timeBuckets = new TimeBuckets(timeBucketConfig);
+    timeBuckets.setInterval('auto');
+    const interval = timeBuckets.getInterval();
+
+    expect(interval.description).toEqual('0 milliseconds');
+    expect(interval.esValue).toEqual(0);
+    expect(interval.esUnit).toEqual('ms');
+    expect(interval.expression).toEqual('0ms');
+  });
+
+  test('getScaledDateFormat', () => {
+    const timeBuckets = new TimeBuckets(timeBucketConfig);
+    timeBuckets.setInterval('20m');
+    timeBuckets.getScaledDateFormat();
+    const format = timeBuckets.getScaledDateFormat();
+    expect(format).toEqual('HH:mm');
+  });
+});
diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts
index c14f02e7decdf..b8d6586652d6b 100644
--- a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts
+++ b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts
@@ -17,11 +17,11 @@
  * under the License.
  */
 
-import _ from 'lodash';
-import moment from 'moment';
+import { isString, isObject as isObjectLodash, isPlainObject, sortBy } from 'lodash';
+import moment, { Moment } from 'moment';
 
-import { IUiSettingsClient } from 'src/core/public';
 import { parseInterval } from '../../../../../../common';
+import { TimeRangeBounds } from '../../../../../query';
 import { calcAutoIntervalLessThan, calcAutoIntervalNear } from './calc_auto_interval';
 import {
   convertDurationToNormalizedEsInterval,
@@ -29,37 +29,30 @@ import {
   EsInterval,
 } from './calc_es_interval';
 
-interface Bounds {
-  min: Date | number | null;
-  max: Date | number | null;
-}
-
 interface TimeBucketsInterval extends moment.Duration {
   // TODO double-check whether all of these are needed
   description: string;
   esValue: EsInterval['value'];
   esUnit: EsInterval['unit'];
   expression: EsInterval['expression'];
-  overflow: moment.Duration | boolean;
-  preScaled?: moment.Duration;
+  preScaled?: TimeBucketsInterval;
   scale?: number;
   scaled?: boolean;
 }
 
 function isObject(o: any): o is Record<string, any> {
-  return _.isObject(o);
-}
-
-function isString(s: any): s is string {
-  return _.isString(s);
+  return isObjectLodash(o);
 }
 
 function isValidMoment(m: any): boolean {
   return m && 'isValid' in m && m.isValid();
 }
 
-interface TimeBucketsConfig {
-  uiSettings: IUiSettingsClient;
+export interface TimeBucketsConfig {
+  'histogram:maxBars': number;
+  'histogram:barTarget': number;
+  dateFormat: string;
+  'dateFormat:scaled': string[][];
 }
 
 /**
@@ -70,108 +63,17 @@ interface TimeBucketsConfig {
  * @param {[type]} display [description]
  */
 export class TimeBuckets {
-  private getConfig: (key: string) => any;
-
-  private _lb: Bounds['min'] = null;
-  private _ub: Bounds['max'] = null;
+  private _timeBucketConfig: TimeBucketsConfig;
+  private _lb: TimeRangeBounds['min'];
+  private _ub: TimeRangeBounds['max'];
   private _originalInterval: string | null = null;
   private _i?: moment.Duration | 'auto';
 
   // because other parts of Kibana arbitrarily add properties
   [key: string]: any;
 
-  static __cached__(self: TimeBuckets) {
-    let cache: any = {};
-    const sameMoment = same(moment.isMoment);
-    const sameDuration = same(moment.isDuration);
-
-    const desc: Record<string, any> = {
-      __cached__: {
-        value: self,
-      },
-    };
-
-    const breakers: Record<string, string> = {
-      setBounds: 'bounds',
-      clearBounds: 'bounds',
-      setInterval: 'interval',
-    };
-
-    const resources: Record<string, any> = {
-      bounds: {
-        setup() {
-          return [self._lb, self._ub];
-        },
-        changes(prev: any) {
-          return !sameMoment(prev[0], self._lb) || !sameMoment(prev[1], self._ub);
-        },
-      },
-      interval: {
-        setup() {
-          return self._i;
-        },
-        changes(prev: any) {
-          return !sameDuration(prev, self._i);
-        },
-      },
-    };
-
-    function cachedGetter(prop: string) {
-      return {
-        value: (...rest: any) => {
-          if (cache.hasOwnProperty(prop)) {
-            return cache[prop];
-          }
-
-          return (cache[prop] = self[prop](...rest));
-        },
-      };
-    }
-
-    function cacheBreaker(prop: string) {
-      const resource = resources[breakers[prop]];
-      const setup = resource.setup;
-      const changes = resource.changes;
-      const fn = self[prop];
-
-      return {
-        value: (...args: any) => {
-          const prev = setup.call(self);
-          const ret = fn.apply(self, ...args);
-
-          if (changes.call(self, prev)) {
-            cache = {};
-          }
-
-          return ret;
-        },
-      };
-    }
-
-    function same(checkType: any) {
-      return function(a: any, b: any) {
-        if (a === b) return true;
-        if (checkType(a) === checkType(b)) return +a === +b;
-        return false;
-      };
-    }
-
-    _.forOwn(TimeBuckets.prototype, (fn, prop) => {
-      if (!prop || prop[0] === '_') return;
-
-      if (breakers.hasOwnProperty(prop)) {
-        desc[prop] = cacheBreaker(prop);
-      } else {
-        desc[prop] = cachedGetter(prop);
-      }
-    });
-
-    return Object.create(self, desc);
-  }
-
-  constructor({ uiSettings }: TimeBucketsConfig) {
-    this.getConfig = (key: string) => uiSettings.get(key);
-    return TimeBuckets.__cached__(this);
+  constructor(timeBucketConfig: TimeBucketsConfig) {
+    this._timeBucketConfig = timeBucketConfig;
   }
 
   /**
@@ -182,10 +84,10 @@ export class TimeBuckets {
    * @return {moment.duration|undefined}
    */
   private getDuration(): moment.Duration | undefined {
-    if (this._ub === null || this._lb === null || !this.hasBounds()) {
+    if (this._ub === undefined || this._lb === undefined || !this.hasBounds()) {
       return;
     }
-    const difference = (this._ub as number) - (this._lb as number);
+    const difference = this._ub.valueOf() - this._lb.valueOf();
     return moment.duration(difference, 'ms');
   }
 
@@ -200,22 +102,20 @@ export class TimeBuckets {
    *
    * @returns {undefined}
    */
-  setBounds(input?: Bounds | Bounds[]) {
+  setBounds(input?: TimeRangeBounds | TimeRangeBounds[]) {
     if (!input) return this.clearBounds();
 
     let bounds;
-    if (_.isPlainObject(input) && !Array.isArray(input)) {
+    if (isPlainObject(input) && !Array.isArray(input)) {
       // accept the response from timefilter.getActiveBounds()
       bounds = [input.min, input.max];
     } else {
       bounds = Array.isArray(input) ? input : [];
     }
 
-    const moments = _(bounds)
-      .map(_.ary(moment, 1))
-      .sortBy(Number);
+    const moments: Moment[] = sortBy(bounds, Number);
 
-    const valid = moments.size() === 2 && moments.every(isValidMoment);
+    const valid = moments.length === 2 && moments.every(isValidMoment);
     if (!valid) {
       this.clearBounds();
       throw new Error('invalid bounds set: ' + input);
@@ -236,7 +136,7 @@ export class TimeBuckets {
    * @return {undefined}
    */
   clearBounds() {
-    this._lb = this._ub = null;
+    this._lb = this._ub = undefined;
   }
 
   /**
@@ -262,7 +162,7 @@ export class TimeBuckets {
    *                      object
    *
    */
-  getBounds(): Bounds | undefined {
+  getBounds(): TimeRangeBounds | undefined {
     if (!this.hasBounds()) return;
     return {
       min: this._lb,
@@ -278,11 +178,10 @@ export class TimeBuckets {
    *  - Any object from src/legacy/ui/agg_types.js
    *  - "auto"
    *  - Pass a valid moment unit
-   *  - a moment.duration object.
    *
    * @param {object|string|moment.duration} input - see desc
    */
-  setInterval(input: null | string | Record<string, any> | moment.Duration) {
+  setInterval(input: null | string | Record<string, any>) {
     let interval = input;
 
     // selection object -> val
@@ -351,7 +250,7 @@ export class TimeBuckets {
     const readInterval = () => {
       const interval = this._i;
       if (moment.isDuration(interval)) return interval;
-      return calcAutoIntervalNear(this.getConfig('histogram:barTarget'), Number(duration));
+      return calcAutoIntervalNear(this._timeBucketConfig['histogram:barTarget'], Number(duration));
     };
 
     const parsedInterval = readInterval();
@@ -362,7 +261,7 @@ export class TimeBuckets {
         return interval;
       }
 
-      const maxLength: number = this.getConfig('histogram:maxBars');
+      const maxLength: number = this._timeBucketConfig['histogram:maxBars'];
       const approxLen = Number(duration) / Number(interval);
 
       let scaled;
@@ -396,10 +295,6 @@ export class TimeBuckets {
         esValue: esInterval.value,
         esUnit: esInterval.unit,
         expression: esInterval.expression,
-        overflow:
-          Number(duration) > Number(interval)
-            ? moment.duration(Number(interval) - Number(duration))
-            : false,
       });
     };
 
@@ -423,7 +318,7 @@ export class TimeBuckets {
    */
   getScaledDateFormat() {
     const interval = this.getInterval();
-    const rules = this.getConfig('dateFormat:scaled');
+    const rules = this._timeBucketConfig['dateFormat:scaled'];
 
     for (let i = rules.length - 1; i >= 0; i--) {
       const rule = rules[i];
@@ -432,6 +327,6 @@ export class TimeBuckets {
       }
     }
 
-    return this.getConfig('dateFormat');
+    return this._timeBucketConfig.dateFormat;
   }
 }
diff --git a/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts b/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts
index 459de66d057d4..9d976784329cc 100644
--- a/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts
+++ b/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
+import moment from 'moment';
 import { IUiSettingsClient } from 'src/core/public';
 import { TimeBuckets } from '../buckets/lib/time_buckets';
 import { toAbsoluteDates, TimeRange } from '../../../../common';
@@ -28,12 +28,17 @@ export function getCalculateAutoTimeExpression(uiSettings: IUiSettingsClient) {
       return;
     }
 
-    const buckets = new TimeBuckets({ uiSettings });
+    const buckets = new TimeBuckets({
+      'histogram:maxBars': uiSettings.get('histogram:maxBars'),
+      'histogram:barTarget': uiSettings.get('histogram:barTarget'),
+      dateFormat: uiSettings.get('dateFormat'),
+      'dateFormat:scaled': uiSettings.get('dateFormat:scaled'),
+    });
 
     buckets.setInterval('auto');
     buckets.setBounds({
-      min: dates.from,
-      max: dates.to,
+      min: moment(dates.from),
+      max: moment(dates.to),
     });
 
     return buckets.getInterval().expression;
diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.ts b/src/plugins/visualizations/public/legacy/build_pipeline.ts
index 18af94c919247..f3192ba3da81f 100644
--- a/src/plugins/visualizations/public/legacy/build_pipeline.ts
+++ b/src/plugins/visualizations/public/legacy/build_pipeline.ts
@@ -94,8 +94,11 @@ const getSchemas = (
   const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => {
     if (isDateHistogramBucketAggConfig(agg)) {
       agg.params.timeRange = timeRange;
-      const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null;
-      agg.buckets.setBounds(agg.fieldIsTimeField() && bounds);
+      const bounds =
+        agg.params.timeRange && agg.fieldIsTimeField()
+          ? timefilter.calculateBounds(agg.params.timeRange)
+          : undefined;
+      agg.buckets.setBounds(bounds);
       agg.buckets.setInterval(agg.params.interval);
     }
 

From 530732c9dd3fa9ab2db6af2c58b52f2a60288a36 Mon Sep 17 00:00:00 2001
From: Robert Oskamp <robert.oskamp@elastic.co>
Date: Thu, 9 Apr 2020 14:03:44 +0200
Subject: [PATCH 13/78] [ML] Functional tests - stabilize typing in mml input
 (#63091)

This PR wraps the model memory value setting during anomaly detection wizards in a retry.
---
 .../services/machine_learning/job_wizard_common.ts        | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/x-pack/test/functional/services/machine_learning/job_wizard_common.ts b/x-pack/test/functional/services/machine_learning/job_wizard_common.ts
index 36181b66786d5..af33ec2301edc 100644
--- a/x-pack/test/functional/services/machine_learning/job_wizard_common.ts
+++ b/x-pack/test/functional/services/machine_learning/job_wizard_common.ts
@@ -330,9 +330,11 @@ export function MachineLearningJobWizardCommonProvider(
         await this.ensureAdvancedSectionOpen();
         subj = advancedSectionSelector(subj);
       }
-      await mlCommon.setValueWithChecks(subj, modelMemoryLimit, { clearWithKeyboard: true });
-      await this.assertModelMemoryLimitValue(modelMemoryLimit, {
-        withAdvancedSection: sectionOptions.withAdvancedSection,
+      await retry.tryForTime(15 * 1000, async () => {
+        await mlCommon.setValueWithChecks(subj, modelMemoryLimit, { clearWithKeyboard: true });
+        await this.assertModelMemoryLimitValue(modelMemoryLimit, {
+          withAdvancedSection: sectionOptions.withAdvancedSection,
+        });
       });
     },
 

From 8d21b6b6f3ccd0388e3a325e96e90f05df0c42b5 Mon Sep 17 00:00:00 2001
From: Joe Reuter <johannes.reuter@elastic.co>
Date: Thu, 9 Apr 2020 14:06:01 +0200
Subject: [PATCH 14/78] Move search source parsing and serializing to data
 (#59919)

---
 ...-plugins-data-public.createsearchsource.md |  15 ++
 .../kibana-plugin-plugins-data-public.md      |   1 +
 ...plugin-plugins-data-public.searchsource.md |   1 +
 ...gins-data-public.searchsource.serialize.md |  27 ++++
 .../kibana/public/discover/build_services.ts  |   1 +
 .../management/saved_object_registry.ts       |   1 +
 .../components/flyout/__jest__/flyout.test.js |   3 +-
 .../objects_table/components/flyout/flyout.js |   3 +-
 .../objects/lib/resolve_saved_objects.test.ts |  87 +++++-----
 .../objects/lib/resolve_saved_objects.ts      |  59 ++++---
 .../public/visualize/np_ready/legacy_app.js   |   1 +
 .../timelion/public/services/saved_sheets.ts  |   1 +
 .../ui/public/new_platform/set_services.ts    |   2 +
 src/plugins/dashboard/public/plugin.tsx       |   3 +-
 .../saved_dashboards/saved_dashboards.ts      |   3 +-
 src/plugins/data/public/index.ts              |   1 +
 src/plugins/data/public/plugin.ts             |   2 +-
 src/plugins/data/public/public.api.md         |  38 +++--
 src/plugins/data/public/search/index.ts       |   1 +
 src/plugins/data/public/search/mocks.ts       |   1 +
 .../data/public/search/search_service.ts      |   5 +-
 .../create_search_source.test.ts              | 151 ++++++++++++++++++
 .../search_source/create_search_source.ts     | 113 +++++++++++++
 .../data/public/search/search_source/index.ts |   1 +
 .../data/public/search/search_source/mocks.ts |   1 +
 .../search_source/search_source.test.ts       |  75 ++++++++-
 .../search/search_source/search_source.ts     |  82 ++++++++++
 src/plugins/data/public/search/types.ts       |   2 +
 src/plugins/saved_objects/public/plugin.ts    |   1 +
 .../saved_object/helpers/apply_es_resp.ts     |  32 +++-
 .../helpers/build_saved_object.ts             |   3 +-
 .../helpers/hydrate_index_pattern.ts          |  10 +-
 .../helpers/parse_search_source.ts            |  97 -----------
 .../helpers/serialize_saved_object.ts         |  62 ++-----
 .../public/saved_object/saved_object.test.ts  |  52 +++---
 src/plugins/saved_objects/public/types.ts     |  10 +-
 src/plugins/visualizations/public/plugin.ts   |   3 +
 .../public/saved_visualizations/_saved_vis.ts |   3 +-
 src/plugins/visualizations/public/services.ts |   2 +
 .../services/gis_map_saved_object_loader.js   |   1 +
 .../use_search_items/use_search_items.ts      |   1 +
 41 files changed, 685 insertions(+), 273 deletions(-)
 create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.createsearchsource.md
 create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md
 create mode 100644 src/plugins/data/public/search/search_source/create_search_source.test.ts
 create mode 100644 src/plugins/data/public/search/search_source/create_search_source.ts
 delete mode 100644 src/plugins/saved_objects/public/saved_object/helpers/parse_search_source.ts

diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.createsearchsource.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.createsearchsource.md
new file mode 100644
index 0000000000000..5c5aa348eecdf
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.createsearchsource.md
@@ -0,0 +1,15 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [createSearchSource](./kibana-plugin-plugins-data-public.createsearchsource.md)
+
+## createSearchSource variable
+
+Deserializes a json string and a set of referenced objects to a `SearchSource` instance. Use this method to re-create the search source serialized using `searchSource.serialize`<!-- -->.
+
+This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service
+
+<b>Signature:</b>
+
+```typescript
+createSearchSource: (indexPatterns: Pick<import("../../index_patterns/index_patterns").IndexPatternsService, "get" | "clearCache" | "getFieldsForTimePattern" | "getFieldsForWildcard" | "getIds" | "getTitles" | "getFields" | "getCache" | "getDefault" | "make">) => (searchSourceJson: string, references: SavedObjectReference[]) => Promise<SearchSource>
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
index 6964c070097c5..fc0dab94a0f65 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
@@ -102,6 +102,7 @@
 |  [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-public.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string |
 |  [connectToQueryState](./kibana-plugin-plugins-data-public.connecttoquerystate.md) | Helper to setup two-way syncing of global data and a state container |
 |  [createSavedQueryService](./kibana-plugin-plugins-data-public.createsavedqueryservice.md) |  |
+|  [createSearchSource](./kibana-plugin-plugins-data-public.createsearchsource.md) | Deserializes a json string and a set of referenced objects to a <code>SearchSource</code> instance. Use this method to re-create the search source serialized using <code>searchSource.serialize</code>.<!-- -->This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service |
 |  [ES\_SEARCH\_STRATEGY](./kibana-plugin-plugins-data-public.es_search_strategy.md) |  |
 |  [esFilters](./kibana-plugin-plugins-data-public.esfilters.md) |  |
 |  [esKuery](./kibana-plugin-plugins-data-public.eskuery.md) |  |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md
index 8e1dbb6e2671d..5f2fc809a5590 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md
@@ -38,6 +38,7 @@ export declare class SearchSource
 |  [getParent()](./kibana-plugin-plugins-data-public.searchsource.getparent.md) |  | Get the parent of this SearchSource  {<!-- -->undefined\|searchSource<!-- -->} |
 |  [getSearchRequestBody()](./kibana-plugin-plugins-data-public.searchsource.getsearchrequestbody.md) |  |  |
 |  [onRequestStart(handler)](./kibana-plugin-plugins-data-public.searchsource.onrequeststart.md) |  | Add a handler that will be notified whenever requests start |
+|  [serialize()](./kibana-plugin-plugins-data-public.searchsource.serialize.md) |  | Serializes the instance to a JSON string and a set of referenced objects. Use this method to get a representation of the search source which can be stored in a saved object.<!-- -->The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named <code>kibanaSavedObjectMeta.searchSourceJSON.index</code> and <code>kibanaSavedObjectMeta.searchSourceJSON.filter[&lt;number&gt;].meta.index</code>.<!-- -->Using <code>createSearchSource</code>, the instance can be re-created. |
 |  [setField(field, value)](./kibana-plugin-plugins-data-public.searchsource.setfield.md) |  |  |
 |  [setFields(newFields)](./kibana-plugin-plugins-data-public.searchsource.setfields.md) |  |  |
 |  [setParent(parent, options)](./kibana-plugin-plugins-data-public.searchsource.setparent.md) |  | Set a searchSource that this source should inherit from |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md
new file mode 100644
index 0000000000000..52d25dec01dfd
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md
@@ -0,0 +1,27 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) &gt; [serialize](./kibana-plugin-plugins-data-public.searchsource.serialize.md)
+
+## SearchSource.serialize() method
+
+Serializes the instance to a JSON string and a set of referenced objects. Use this method to get a representation of the search source which can be stored in a saved object.
+
+The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named `kibanaSavedObjectMeta.searchSourceJSON.index` and `kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index`<!-- -->.
+
+Using `createSearchSource`<!-- -->, the instance can be re-created.
+
+<b>Signature:</b>
+
+```typescript
+serialize(): {
+        searchSourceJSON: string;
+        references: SavedObjectReference[];
+    };
+```
+<b>Returns:</b>
+
+`{
+        searchSourceJSON: string;
+        references: SavedObjectReference[];
+    }`
+
diff --git a/src/legacy/core_plugins/kibana/public/discover/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/build_services.ts
index 180ff13cdddc0..a3a99a0ded523 100644
--- a/src/legacy/core_plugins/kibana/public/discover/build_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/build_services.ts
@@ -72,6 +72,7 @@ export async function buildServices(
   const services = {
     savedObjectsClient: core.savedObjects.client,
     indexPatterns: plugins.data.indexPatterns,
+    search: plugins.data.search,
     chrome: core.chrome,
     overlays: core.overlays,
   };
diff --git a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts b/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
index 7261b2ba03372..705be68a141e7 100644
--- a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
+++ b/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
@@ -56,6 +56,7 @@ export const savedObjectManagementRegistry: ISavedObjectsManagementRegistry = {
 const services = {
   savedObjectsClient: npStart.core.savedObjects.client,
   indexPatterns: npStart.plugins.data.indexPatterns,
+  search: npStart.plugins.data.search,
   chrome: npStart.core.chrome,
   overlays: npStart.core.overlays,
 };
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
index 5d14c4609b918..0d16e0ae35dd6 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
@@ -519,7 +519,8 @@ describe('Flyout', () => {
       expect(resolveIndexPatternConflicts).toHaveBeenCalledWith(
         component.instance().resolutions,
         mockConflictedIndexPatterns,
-        true
+        true,
+        defaultProps.indexPatterns
       );
       expect(saveObjects).toHaveBeenCalledWith(
         mockConflictedSavedObjectsLinkedToSavedSearches,
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js
index 105c279218375..da2221bb54203 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js
@@ -358,7 +358,8 @@ export class Flyout extends Component {
           importCount += await resolveIndexPatternConflicts(
             resolutions,
             conflictedIndexPatterns,
-            isOverwriteAllChecked
+            isOverwriteAllChecked,
+            this.props.indexPatterns
           );
         }
         this.setState({
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts
index 8243aa69ac082..dc6d2643145ff 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts
@@ -84,7 +84,7 @@ describe('resolveSavedObjects', () => {
         },
       } as unknown) as IndexPatternsContract;
 
-      const services = [
+      const services = ([
         {
           type: 'search',
           get: async () => {
@@ -124,7 +124,7 @@ describe('resolveSavedObjects', () => {
             };
           },
         },
-      ] as SavedObjectLoader[];
+      ] as unknown) as SavedObjectLoader[];
 
       const overwriteAll = false;
 
@@ -176,7 +176,7 @@ describe('resolveSavedObjects', () => {
         },
       } as unknown) as IndexPatternsContract;
 
-      const services = [
+      const services = ([
         {
           type: 'search',
           get: async () => {
@@ -217,7 +217,7 @@ describe('resolveSavedObjects', () => {
             };
           },
         },
-      ] as SavedObjectLoader[];
+      ] as unknown) as SavedObjectLoader[];
 
       const overwriteAll = false;
 
@@ -237,33 +237,38 @@ describe('resolveSavedObjects', () => {
 
   describe('resolveIndexPatternConflicts', () => {
     it('should resave resolutions', async () => {
-      const hydrateIndexPattern = jest.fn();
       const save = jest.fn();
 
-      const conflictedIndexPatterns = [
+      const conflictedIndexPatterns = ([
         {
           obj: {
-            searchSource: {
-              getOwnField: (field: string) => {
-                return field === 'index' ? '1' : undefined;
+            save,
+          },
+          doc: {
+            _source: {
+              kibanaSavedObjectMeta: {
+                searchSourceJSON: JSON.stringify({
+                  index: '1',
+                }),
               },
             },
-            hydrateIndexPattern,
-            save,
           },
         },
         {
           obj: {
-            searchSource: {
-              getOwnField: (field: string) => {
-                return field === 'index' ? '3' : undefined;
+            save,
+          },
+          doc: {
+            _source: {
+              kibanaSavedObjectMeta: {
+                searchSourceJSON: JSON.stringify({
+                  index: '3',
+                }),
               },
             },
-            hydrateIndexPattern,
-            save,
           },
         },
-      ];
+      ] as unknown) as Array<{ obj: SavedObject; doc: any }>;
 
       const resolutions = [
         {
@@ -282,43 +287,49 @@ describe('resolveSavedObjects', () => {
 
       const overwriteAll = false;
 
-      await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll);
-      expect(hydrateIndexPattern.mock.calls.length).toBe(2);
+      await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll, ({
+        get: (id: string) => Promise.resolve({ id }),
+      } as unknown) as IndexPatternsContract);
+      expect(conflictedIndexPatterns[0].obj.searchSource!.getField('index')!.id).toEqual('2');
+      expect(conflictedIndexPatterns[1].obj.searchSource!.getField('index')!.id).toEqual('4');
       expect(save.mock.calls.length).toBe(2);
       expect(save).toHaveBeenCalledWith({ confirmOverwrite: !overwriteAll });
-      expect(hydrateIndexPattern).toHaveBeenCalledWith('2');
-      expect(hydrateIndexPattern).toHaveBeenCalledWith('4');
     });
 
     it('should resolve filter index conflicts', async () => {
-      const hydrateIndexPattern = jest.fn();
       const save = jest.fn();
 
-      const conflictedIndexPatterns = [
+      const conflictedIndexPatterns = ([
         {
           obj: {
-            searchSource: {
-              getOwnField: (field: string) => {
-                return field === 'index' ? '1' : [{ meta: { index: 'filterIndex' } }];
+            save,
+          },
+          doc: {
+            _source: {
+              kibanaSavedObjectMeta: {
+                searchSourceJSON: JSON.stringify({
+                  index: '1',
+                  filter: [{ meta: { index: 'filterIndex' } }],
+                }),
               },
-              setField: jest.fn(),
             },
-            hydrateIndexPattern,
-            save,
           },
         },
         {
           obj: {
-            searchSource: {
-              getOwnField: (field: string) => {
-                return field === 'index' ? '3' : undefined;
+            save,
+          },
+          doc: {
+            _source: {
+              kibanaSavedObjectMeta: {
+                searchSourceJSON: JSON.stringify({
+                  index: '3',
+                }),
               },
             },
-            hydrateIndexPattern,
-            save,
           },
         },
-      ];
+      ] as unknown) as Array<{ obj: SavedObject; doc: any }>;
 
       const resolutions = [
         {
@@ -337,9 +348,11 @@ describe('resolveSavedObjects', () => {
 
       const overwriteAll = false;
 
-      await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll);
+      await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll, ({
+        get: (id: string) => Promise.resolve({ id }),
+      } as unknown) as IndexPatternsContract);
 
-      expect(conflictedIndexPatterns[0].obj.searchSource.setField).toHaveBeenCalledWith('filter', [
+      expect(conflictedIndexPatterns[0].obj.searchSource!.getField('filter')).toEqual([
         { meta: { index: 'newFilterIndex' } },
       ]);
       expect(save.mock.calls.length).toBe(2);
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts
index 902de654f5f85..d9473367f7502 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts
@@ -18,12 +18,17 @@
  */
 
 import { i18n } from '@kbn/i18n';
-import { OverlayStart } from 'src/core/public';
+import { cloneDeep } from 'lodash';
+import { OverlayStart, SavedObjectReference } from 'src/core/public';
 import {
   SavedObject,
   SavedObjectLoader,
 } from '../../../../../../../../plugins/saved_objects/public';
-import { IndexPatternsContract, IIndexPattern } from '../../../../../../../../plugins/data/public';
+import {
+  IndexPatternsContract,
+  IIndexPattern,
+  createSearchSource,
+} from '../../../../../../../../plugins/data/public';
 
 type SavedObjectsRawDoc = Record<string, any>;
 
@@ -126,7 +131,7 @@ async function importIndexPattern(
 async function importDocument(obj: SavedObject, doc: SavedObjectsRawDoc, overwriteAll: boolean) {
   await obj.applyESResp({
     references: doc._references || [],
-    ...doc,
+    ...cloneDeep(doc),
   });
   return await obj.save({ confirmOverwrite: !overwriteAll });
 }
@@ -160,41 +165,57 @@ async function awaitEachItemInParallel<T, R>(list: T[], op: (item: T) => R) {
 export async function resolveIndexPatternConflicts(
   resolutions: Array<{ oldId: string; newId: string }>,
   conflictedIndexPatterns: any[],
-  overwriteAll: boolean
+  overwriteAll: boolean,
+  indexPatterns: IndexPatternsContract
 ) {
   let importCount = 0;
 
-  await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj }) => {
-    // Resolve search index reference:
-    let oldIndexId = obj.searchSource.getOwnField('index');
-    // Depending on the object, this can either be the raw id or the actual index pattern object
-    if (typeof oldIndexId !== 'string') {
-      oldIndexId = oldIndexId.id;
-    }
-    let resolution = resolutions.find(({ oldId }) => oldId === oldIndexId);
-    if (resolution) {
-      const newIndexId = resolution.newId;
-      await obj.hydrateIndexPattern(newIndexId);
+  await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj, doc }) => {
+    const serializedSearchSource = JSON.parse(
+      doc._source.kibanaSavedObjectMeta?.searchSourceJSON || '{}'
+    );
+    const oldIndexId = serializedSearchSource.index;
+    let allResolved = true;
+    const inlineResolution = resolutions.find(({ oldId }) => oldId === oldIndexId);
+    if (inlineResolution) {
+      serializedSearchSource.index = inlineResolution.newId;
+    } else {
+      allResolved = false;
     }
 
     // Resolve filter index reference:
-    const filter = (obj.searchSource.getOwnField('filter') || []).map((f: any) => {
+    const filter = (serializedSearchSource.filter || []).map((f: any) => {
       if (!(f.meta && f.meta.index)) {
         return f;
       }
 
-      resolution = resolutions.find(({ oldId }) => oldId === f.meta.index);
+      const resolution = resolutions.find(({ oldId }) => oldId === f.meta.index);
       return resolution ? { ...f, ...{ meta: { ...f.meta, index: resolution.newId } } } : f;
     });
 
     if (filter.length > 0) {
-      obj.searchSource.setField('filter', filter);
+      serializedSearchSource.filter = filter;
     }
 
-    if (!resolution) {
+    const replacedReferences = (doc._references || []).map((reference: SavedObjectReference) => {
+      const resolution = resolutions.find(({ oldId }) => oldId === reference.id);
+      if (resolution) {
+        return { ...reference, id: resolution.newId };
+      } else {
+        allResolved = false;
+      }
+
+      return reference;
+    });
+
+    if (!allResolved) {
       // The user decided to skip this conflict so do nothing
       return;
     }
+    obj.searchSource = await createSearchSource(indexPatterns)(
+      JSON.stringify(serializedSearchSource),
+      replacedReferences
+    );
     if (await saveObject(obj, overwriteAll)) {
       importCount++;
     }
diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js
index 7c9ab32ab2f72..a710d3e318749 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js
@@ -71,6 +71,7 @@ const getResolvedResults = deps => {
           return createSavedSearchesLoader({
             savedObjectsClient: core.savedObjects.client,
             indexPatterns: data.indexPatterns,
+            search: data.search,
             chrome: core.chrome,
             overlays: core.overlays,
           }).get(results.vis.data.savedSearchId);
diff --git a/src/legacy/core_plugins/timelion/public/services/saved_sheets.ts b/src/legacy/core_plugins/timelion/public/services/saved_sheets.ts
index 201b21f932988..e7f431a178ea0 100644
--- a/src/legacy/core_plugins/timelion/public/services/saved_sheets.ts
+++ b/src/legacy/core_plugins/timelion/public/services/saved_sheets.ts
@@ -28,6 +28,7 @@ const savedObjectsClient = npStart.core.savedObjects.client;
 const services = {
   savedObjectsClient,
   indexPatterns: npStart.plugins.data.indexPatterns,
+  search: npStart.plugins.data.search,
   chrome: npStart.core.chrome,
   overlays: npStart.core.overlays,
 };
diff --git a/src/legacy/ui/public/new_platform/set_services.ts b/src/legacy/ui/public/new_platform/set_services.ts
index 8cf015d5dff5c..400f31e73ffa1 100644
--- a/src/legacy/ui/public/new_platform/set_services.ts
+++ b/src/legacy/ui/public/new_platform/set_services.ts
@@ -72,9 +72,11 @@ export function setStartServices(npStart: NpStart) {
   visualizationsServices.setAggs(npStart.plugins.data.search.aggs);
   visualizationsServices.setOverlays(npStart.core.overlays);
   visualizationsServices.setChrome(npStart.core.chrome);
+  visualizationsServices.setSearch(npStart.plugins.data.search);
   const savedVisualizationsLoader = createSavedVisLoader({
     savedObjectsClient: npStart.core.savedObjects.client,
     indexPatterns: npStart.plugins.data.indexPatterns,
+    search: npStart.plugins.data.search,
     chrome: npStart.core.chrome,
     overlays: npStart.core.overlays,
     visualizationTypes: visualizationsServices.getTypes(),
diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx
index c98fa612dc7af..322d734d9f39f 100644
--- a/src/plugins/dashboard/public/plugin.tsx
+++ b/src/plugins/dashboard/public/plugin.tsx
@@ -284,7 +284,7 @@ export class DashboardPlugin
     const { notifications } = core;
     const {
       uiActions,
-      data: { indexPatterns },
+      data: { indexPatterns, search },
     } = plugins;
 
     const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, core.uiSettings);
@@ -300,6 +300,7 @@ export class DashboardPlugin
     const savedDashboardLoader = createSavedDashboardLoader({
       savedObjectsClient: core.savedObjects.client,
       indexPatterns,
+      search,
       chrome: core.chrome,
       overlays: core.overlays,
     });
diff --git a/src/plugins/dashboard/public/saved_dashboards/saved_dashboards.ts b/src/plugins/dashboard/public/saved_dashboards/saved_dashboards.ts
index 2a1e64fa88a02..09357072a13a6 100644
--- a/src/plugins/dashboard/public/saved_dashboards/saved_dashboards.ts
+++ b/src/plugins/dashboard/public/saved_dashboards/saved_dashboards.ts
@@ -18,13 +18,14 @@
  */
 
 import { SavedObjectsClientContract, ChromeStart, OverlayStart } from 'kibana/public';
-import { IndexPatternsContract } from '../../../../plugins/data/public';
+import { DataPublicPluginStart, IndexPatternsContract } from '../../../../plugins/data/public';
 import { SavedObjectLoader } from '../../../../plugins/saved_objects/public';
 import { createSavedDashboardClass } from './saved_dashboard';
 
 interface Services {
   savedObjectsClient: SavedObjectsClientContract;
   indexPatterns: IndexPatternsContract;
+  search: DataPublicPluginStart['search'];
   chrome: ChromeStart;
   overlays: OverlayStart;
 }
diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts
index efafea44167d4..06a46065baa84 100644
--- a/src/plugins/data/public/index.ts
+++ b/src/plugins/data/public/index.ts
@@ -366,6 +366,7 @@ export {
   SearchStrategyProvider,
   ISearchSource,
   SearchSource,
+  createSearchSource,
   SearchSourceFields,
   EsQuerySortValue,
   SortDirection,
diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts
index 15067077afc43..2ebe377b3b32f 100644
--- a/src/plugins/data/public/plugin.ts
+++ b/src/plugins/data/public/plugin.ts
@@ -155,7 +155,7 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli
     const query = this.queryService.start(savedObjects);
     setQueryService(query);
 
-    const search = this.searchService.start(core);
+    const search = this.searchService.start(core, indexPatterns);
     setSearchService(search);
 
     uiActions.attachAction(APPLY_FILTER_TRIGGER, uiActions.getAction(ACTION_GLOBAL_APPLY_FILTER));
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md
index 9d7428f6432b1..cef82b27b1b5b 100644
--- a/src/plugins/data/public/public.api.md
+++ b/src/plugins/data/public/public.api.md
@@ -45,6 +45,7 @@ import * as React_2 from 'react';
 import { Required } from '@kbn/utility-types';
 import * as Rx from 'rxjs';
 import { SavedObject as SavedObject_2 } from 'src/core/public';
+import { SavedObjectReference } from 'kibana/public';
 import { SavedObjectsClientContract } from 'src/core/public';
 import { SearchParams } from 'elasticsearch';
 import { SearchResponse as SearchResponse_2 } from 'elasticsearch';
@@ -209,6 +210,9 @@ export const connectToQueryState: <S extends QueryState>({ timefilter: { timefil
 // @public (undocumented)
 export const createSavedQueryService: (savedObjectsClient: Pick<import("../../../../../core/public").SavedObjectsClient, "update" | "find" | "get" | "delete" | "create" | "bulkCreate" | "bulkGet" | "bulkUpdate">) => SavedQueryService;
 
+// @public
+export const createSearchSource: (indexPatterns: Pick<import("../../index_patterns/index_patterns").IndexPatternsService, "get" | "clearCache" | "getFieldsForTimePattern" | "getFieldsForWildcard" | "getIds" | "getTitles" | "getFields" | "getCache" | "getDefault" | "make">) => (searchSourceJson: string, references: SavedObjectReference[]) => Promise<SearchSource>;
+
 // Warning: (ae-missing-release-tag) "CustomFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
 //
 // @public (undocumented)
@@ -1667,6 +1671,10 @@ export class SearchSource {
     // (undocumented)
     history: SearchRequest[];
     onRequestStart(handler: (searchSource: ISearchSource, options?: FetchOptions) => Promise<unknown>): void;
+    serialize(): {
+        searchSourceJSON: string;
+        references: SavedObjectReference[];
+    };
     // (undocumented)
     setField<K extends keyof SearchSourceFields>(field: K, value: SearchSourceFields[K]): this;
     // (undocumented)
@@ -1881,21 +1889,21 @@ export type TSearchStrategyProvider<T extends TStrategyTypes> = (context: ISearc
 // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts
 // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts
 // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
 // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
 // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts
 // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts
diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts
index 1687d749f46e2..cce973d632f41 100644
--- a/src/plugins/data/public/search/index.ts
+++ b/src/plugins/data/public/search/index.ts
@@ -54,6 +54,7 @@ export {
   SearchSourceFields,
   EsQuerySortValue,
   SortDirection,
+  createSearchSource,
 } from './search_source';
 
 export { SearchInterceptor } from './search_interceptor';
diff --git a/src/plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/mocks.ts
index b70e889066a45..cb1c625a72959 100644
--- a/src/plugins/data/public/search/mocks.ts
+++ b/src/plugins/data/public/search/mocks.ts
@@ -33,6 +33,7 @@ export const searchStartMock: jest.Mocked<ISearchStart> = {
   aggs: searchAggsStartMock(),
   setInterceptor: jest.fn(),
   search: jest.fn(),
+  createSearchSource: jest.fn(),
   __LEGACY: {
     AggConfig: jest.fn() as any,
     AggType: jest.fn(),
diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts
index 42f31ef450d28..6124682184821 100644
--- a/src/plugins/data/public/search/search_service.ts
+++ b/src/plugins/data/public/search/search_service.ts
@@ -25,6 +25,8 @@ import { TStrategyTypes } from './strategy_types';
 import { getEsClient, LegacyApiCaller } from './es_client';
 import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search';
 import { esSearchStrategyProvider } from './es_search/es_search_strategy';
+import { IndexPatternsContract } from '../index_patterns/index_patterns';
+import { createSearchSource } from './search_source';
 import { QuerySetup } from '../query/query_service';
 import { GetInternalStartServicesFn } from '../types';
 import { SearchInterceptor } from './search_interceptor';
@@ -108,7 +110,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
     };
   }
 
-  public start(core: CoreStart): ISearchStart {
+  public start(core: CoreStart, indexPatterns: IndexPatternsContract): ISearchStart {
     /**
      * A global object that intercepts all searches and provides convenience methods for cancelling
      * all pending search requests, as well as getting the number of pending search requests.
@@ -145,6 +147,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
         // TODO: should an intercepror have a destroy method?
         this.searchInterceptor = searchInterceptor;
       },
+      createSearchSource: createSearchSource(indexPatterns),
       __LEGACY: {
         esClient: this.esClient!,
         AggConfig,
diff --git a/src/plugins/data/public/search/search_source/create_search_source.test.ts b/src/plugins/data/public/search/search_source/create_search_source.test.ts
new file mode 100644
index 0000000000000..d49ce5a0d11f8
--- /dev/null
+++ b/src/plugins/data/public/search/search_source/create_search_source.test.ts
@@ -0,0 +1,151 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { createSearchSource as createSearchSourceFactory } from './create_search_source';
+import { IIndexPattern } from '../../../common/index_patterns';
+import { IndexPatternsContract } from '../../index_patterns/index_patterns';
+import { Filter } from '../../../common/es_query/filters';
+
+describe('createSearchSource', function() {
+  let createSearchSource: ReturnType<typeof createSearchSourceFactory>;
+  const indexPatternMock: IIndexPattern = {} as IIndexPattern;
+  let indexPatternContractMock: jest.Mocked<IndexPatternsContract>;
+
+  beforeEach(() => {
+    indexPatternContractMock = ({
+      get: jest.fn().mockReturnValue(Promise.resolve(indexPatternMock)),
+    } as unknown) as jest.Mocked<IndexPatternsContract>;
+    createSearchSource = createSearchSourceFactory(indexPatternContractMock);
+  });
+
+  it('should fail if JSON is invalid', () => {
+    expect(createSearchSource('{', [])).rejects.toThrow();
+    expect(createSearchSource('0', [])).rejects.toThrow();
+    expect(createSearchSource('"abcdefg"', [])).rejects.toThrow();
+  });
+
+  it('should set fields', async () => {
+    const searchSource = await createSearchSource(
+      JSON.stringify({
+        highlightAll: true,
+        query: {
+          query: '',
+          language: 'kuery',
+        },
+      }),
+      []
+    );
+    expect(searchSource.getOwnField('highlightAll')).toBe(true);
+    expect(searchSource.getOwnField('query')).toEqual({
+      query: '',
+      language: 'kuery',
+    });
+  });
+
+  it('should resolve referenced index pattern', async () => {
+    const searchSource = await createSearchSource(
+      JSON.stringify({
+        indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+      }),
+      [
+        {
+          id: '123-456',
+          type: 'index-pattern',
+          name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+        },
+      ]
+    );
+    expect(indexPatternContractMock.get).toHaveBeenCalledWith('123-456');
+    expect(searchSource.getOwnField('index')).toBe(indexPatternMock);
+  });
+
+  it('should set filters and resolve referenced index patterns', async () => {
+    const searchSource = await createSearchSource(
+      JSON.stringify({
+        filter: [
+          {
+            meta: {
+              alias: null,
+              negate: false,
+              disabled: false,
+              type: 'phrase',
+              key: 'category.keyword',
+              params: {
+                query: "Men's Clothing",
+              },
+              indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+            },
+            query: {
+              match_phrase: {
+                'category.keyword': "Men's Clothing",
+              },
+            },
+            $state: {
+              store: 'appState',
+            },
+          },
+        ],
+      }),
+      [
+        {
+          id: '123-456',
+          type: 'index-pattern',
+          name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+        },
+      ]
+    );
+    const filters = searchSource.getOwnField('filter') as Filter[];
+    expect(filters[0]).toMatchInlineSnapshot(`
+      Object {
+        "$state": Object {
+          "store": "appState",
+        },
+        "meta": Object {
+          "alias": null,
+          "disabled": false,
+          "index": "123-456",
+          "key": "category.keyword",
+          "negate": false,
+          "params": Object {
+            "query": "Men's Clothing",
+          },
+          "type": "phrase",
+        },
+        "query": Object {
+          "match_phrase": Object {
+            "category.keyword": "Men's Clothing",
+          },
+        },
+      }
+    `);
+  });
+
+  it('should migrate legacy queries on the fly', async () => {
+    const searchSource = await createSearchSource(
+      JSON.stringify({
+        highlightAll: true,
+        query: 'a:b',
+      }),
+      []
+    );
+    expect(searchSource.getOwnField('query')).toEqual({
+      query: 'a:b',
+      language: 'lucene',
+    });
+  });
+});
diff --git a/src/plugins/data/public/search/search_source/create_search_source.ts b/src/plugins/data/public/search/search_source/create_search_source.ts
new file mode 100644
index 0000000000000..35b7ac4eb9762
--- /dev/null
+++ b/src/plugins/data/public/search/search_source/create_search_source.ts
@@ -0,0 +1,113 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import _ from 'lodash';
+import { SavedObjectReference } from 'kibana/public';
+import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
+import { InvalidJSONProperty } from '../../../../kibana_utils/public';
+import { SearchSource } from './search_source';
+import { IndexPatternsContract } from '../../index_patterns/index_patterns';
+import { SearchSourceFields } from './types';
+
+/**
+ * Deserializes a json string and a set of referenced objects to a `SearchSource` instance.
+ * Use this method to re-create the search source serialized using `searchSource.serialize`.
+ *
+ * This function is a factory function that returns the actual utility when calling it with the
+ * required service dependency (index patterns contract). A pre-wired version is also exposed in
+ * the start contract of the data plugin as part of the search service
+ *
+ * @param indexPatterns The index patterns contract of the data plugin
+ *
+ * @return Wired utility function taking two parameters `searchSourceJson`, the json string
+ * returned by `serializeSearchSource` and `references`, a list of references including the ones
+ * returned by `serializeSearchSource`.
+ *
+ * @public */
+export const createSearchSource = (indexPatterns: IndexPatternsContract) => async (
+  searchSourceJson: string,
+  references: SavedObjectReference[]
+) => {
+  const searchSource = new SearchSource();
+
+  // if we have a searchSource, set its values based on the searchSourceJson field
+  let searchSourceValues: Record<string, unknown>;
+  try {
+    searchSourceValues = JSON.parse(searchSourceJson);
+  } catch (e) {
+    throw new InvalidJSONProperty(
+      `Invalid JSON in search source. ${e.message} JSON: ${searchSourceJson}`
+    );
+  }
+
+  // This detects a scenario where documents with invalid JSON properties have been imported into the saved object index.
+  // (This happened in issue #20308)
+  if (!searchSourceValues || typeof searchSourceValues !== 'object') {
+    throw new InvalidJSONProperty('Invalid JSON in search source.');
+  }
+
+  // Inject index id if a reference is saved
+  if (searchSourceValues.indexRefName) {
+    const reference = references.find(ref => ref.name === searchSourceValues.indexRefName);
+    if (!reference) {
+      throw new Error(`Could not find reference for ${searchSourceValues.indexRefName}`);
+    }
+    searchSourceValues.index = reference.id;
+    delete searchSourceValues.indexRefName;
+  }
+
+  if (searchSourceValues.filter && Array.isArray(searchSourceValues.filter)) {
+    searchSourceValues.filter.forEach((filterRow: any) => {
+      if (!filterRow.meta || !filterRow.meta.indexRefName) {
+        return;
+      }
+      const reference = references.find((ref: any) => ref.name === filterRow.meta.indexRefName);
+      if (!reference) {
+        throw new Error(`Could not find reference for ${filterRow.meta.indexRefName}`);
+      }
+      filterRow.meta.index = reference.id;
+      delete filterRow.meta.indexRefName;
+    });
+  }
+
+  if (searchSourceValues.index && typeof searchSourceValues.index === 'string') {
+    searchSourceValues.index = await indexPatterns.get(searchSourceValues.index);
+  }
+
+  const searchSourceFields = searchSource.getFields();
+  const fnProps = _.transform(
+    searchSourceFields,
+    function(dynamic, val, name) {
+      if (_.isFunction(val) && name) dynamic[name] = val;
+    },
+    {}
+  );
+
+  // This assignment might hide problems because the type of values passed from the parsed JSON
+  // might not fit the SearchSourceFields interface.
+  const newFields: SearchSourceFields = _.defaults(searchSourceValues, fnProps);
+
+  searchSource.setFields(newFields);
+  const query = searchSource.getOwnField('query');
+
+  if (typeof query !== 'undefined') {
+    searchSource.setField('query', migrateLegacyQuery(query));
+  }
+
+  return searchSource;
+};
diff --git a/src/plugins/data/public/search/search_source/index.ts b/src/plugins/data/public/search/search_source/index.ts
index 10f1b2bc332e1..0e9f530d0968a 100644
--- a/src/plugins/data/public/search/search_source/index.ts
+++ b/src/plugins/data/public/search/search_source/index.ts
@@ -18,4 +18,5 @@
  */
 
 export * from './search_source';
+export { createSearchSource } from './create_search_source';
 export { SortDirection, EsQuerySortValue, SearchSourceFields } from './types';
diff --git a/src/plugins/data/public/search/search_source/mocks.ts b/src/plugins/data/public/search/search_source/mocks.ts
index 700bea741bd6a..1ef7c1187a9e0 100644
--- a/src/plugins/data/public/search/search_source/mocks.ts
+++ b/src/plugins/data/public/search/search_source/mocks.ts
@@ -37,4 +37,5 @@ export const searchSourceMock: MockedKeys<ISearchSource> = {
   getSearchRequestBody: jest.fn(),
   destroy: jest.fn(),
   history: [],
+  serialize: jest.fn(),
 };
diff --git a/src/plugins/data/public/search/search_source/search_source.test.ts b/src/plugins/data/public/search/search_source/search_source.test.ts
index fcd116a3f4121..6bad093d31402 100644
--- a/src/plugins/data/public/search/search_source/search_source.test.ts
+++ b/src/plugins/data/public/search/search_source/search_source.test.ts
@@ -18,7 +18,7 @@
  */
 
 import { SearchSource } from './search_source';
-import { IndexPattern } from '../..';
+import { IndexPattern, SortDirection } from '../..';
 import { mockDataServices } from '../aggs/test_helpers';
 
 jest.mock('../fetch', () => ({
@@ -150,4 +150,77 @@ describe('SearchSource', function() {
       expect(parentFn).toBeCalledWith(searchSource, options);
     });
   });
+
+  describe('#serialize', function() {
+    it('should reference index patterns', () => {
+      const indexPattern123 = { id: '123' } as IndexPattern;
+      const searchSource = new SearchSource();
+      searchSource.setField('index', indexPattern123);
+      const { searchSourceJSON, references } = searchSource.serialize();
+      expect(references[0].id).toEqual('123');
+      expect(references[0].type).toEqual('index-pattern');
+      expect(JSON.parse(searchSourceJSON).indexRefName).toEqual(references[0].name);
+    });
+
+    it('should add other fields', () => {
+      const searchSource = new SearchSource();
+      searchSource.setField('highlightAll', true);
+      searchSource.setField('from', 123456);
+      const { searchSourceJSON } = searchSource.serialize();
+      expect(JSON.parse(searchSourceJSON).highlightAll).toEqual(true);
+      expect(JSON.parse(searchSourceJSON).from).toEqual(123456);
+    });
+
+    it('should omit sort and size', () => {
+      const searchSource = new SearchSource();
+      searchSource.setField('highlightAll', true);
+      searchSource.setField('from', 123456);
+      searchSource.setField('sort', { field: SortDirection.asc });
+      searchSource.setField('size', 200);
+      const { searchSourceJSON } = searchSource.serialize();
+      expect(Object.keys(JSON.parse(searchSourceJSON))).toEqual(['highlightAll', 'from']);
+    });
+
+    it('should serialize filters', () => {
+      const searchSource = new SearchSource();
+      const filter = [
+        {
+          query: 'query',
+          meta: {
+            alias: 'alias',
+            disabled: false,
+            negate: false,
+          },
+        },
+      ];
+      searchSource.setField('filter', filter);
+      const { searchSourceJSON } = searchSource.serialize();
+      expect(JSON.parse(searchSourceJSON).filter).toEqual(filter);
+    });
+
+    it('should reference index patterns in filters separately from index field', () => {
+      const searchSource = new SearchSource();
+      const indexPattern123 = { id: '123' } as IndexPattern;
+      searchSource.setField('index', indexPattern123);
+      const filter = [
+        {
+          query: 'query',
+          meta: {
+            alias: 'alias',
+            disabled: false,
+            negate: false,
+            index: '456',
+          },
+        },
+      ];
+      searchSource.setField('filter', filter);
+      const { searchSourceJSON, references } = searchSource.serialize();
+      expect(references[0].id).toEqual('123');
+      expect(references[0].type).toEqual('index-pattern');
+      expect(JSON.parse(searchSourceJSON).indexRefName).toEqual(references[0].name);
+      expect(references[1].id).toEqual('456');
+      expect(references[1].type).toEqual('index-pattern');
+      expect(JSON.parse(searchSourceJSON).filter[0].meta.indexRefName).toEqual(references[1].name);
+    });
+  });
 });
diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts
index 0c3321f03dabc..c70db7bb82ef7 100644
--- a/src/plugins/data/public/search/search_source/search_source.ts
+++ b/src/plugins/data/public/search/search_source/search_source.ts
@@ -70,6 +70,7 @@
  */
 
 import _ from 'lodash';
+import { SavedObjectReference } from 'kibana/public';
 import { normalizeSortRequest } from './normalize_sort_request';
 import { filterDocvalueFields } from './filter_docvalue_fields';
 import { fieldWildcardFilter } from '../../../../kibana_utils/public';
@@ -419,4 +420,85 @@ export class SearchSource {
 
     return searchRequest;
   }
+
+  /**
+   * Serializes the instance to a JSON string and a set of referenced objects.
+   * Use this method to get a representation of the search source which can be stored in a saved object.
+   *
+   * The references returned by this function can be mixed with other references in the same object,
+   * however make sure there are no name-collisions. The references will be named `kibanaSavedObjectMeta.searchSourceJSON.index`
+   * and `kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index`.
+   *
+   * Using `createSearchSource`, the instance can be re-created.
+   * @param searchSource The search source to serialize
+   * @public */
+  public serialize() {
+    const references: SavedObjectReference[] = [];
+
+    const {
+      filter: originalFilters,
+      ...searchSourceFields
+    }: Omit<SearchSourceFields, 'sort' | 'size'> = _.omit(this.getFields(), ['sort', 'size']);
+    let serializedSearchSourceFields: Omit<SearchSourceFields, 'sort' | 'size' | 'filter'> & {
+      indexRefName?: string;
+      filter?: Array<Omit<Filter, 'meta'> & { meta: Filter['meta'] & { indexRefName?: string } }>;
+    } = searchSourceFields;
+    if (searchSourceFields.index) {
+      const indexId = searchSourceFields.index.id!;
+      const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
+      references.push({
+        name: refName,
+        type: 'index-pattern',
+        id: indexId,
+      });
+      serializedSearchSourceFields = {
+        ...serializedSearchSourceFields,
+        indexRefName: refName,
+        index: undefined,
+      };
+    }
+    if (originalFilters) {
+      const filters = this.getFilters(originalFilters);
+      serializedSearchSourceFields = {
+        ...serializedSearchSourceFields,
+        filter: filters.map((filterRow, i) => {
+          if (!filterRow.meta || !filterRow.meta.index) {
+            return filterRow;
+          }
+          const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`;
+          references.push({
+            name: refName,
+            type: 'index-pattern',
+            id: filterRow.meta.index,
+          });
+          return {
+            ...filterRow,
+            meta: {
+              ...filterRow.meta,
+              indexRefName: refName,
+              index: undefined,
+            },
+          };
+        }),
+      };
+    }
+
+    return { searchSourceJSON: JSON.stringify(serializedSearchSourceFields), references };
+  }
+
+  private getFilters(filterField: SearchSourceFields['filter']): Filter[] {
+    if (!filterField) {
+      return [];
+    }
+
+    if (Array.isArray(filterField)) {
+      return filterField;
+    }
+
+    if (_.isFunction(filterField)) {
+      return this.getFilters(filterField());
+    }
+
+    return [filterField];
+  }
 }
diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts
index 03cbfa9f8ed84..ba6e44f47b75e 100644
--- a/src/plugins/data/public/search/types.ts
+++ b/src/plugins/data/public/search/types.ts
@@ -18,6 +18,7 @@
  */
 
 import { CoreStart } from 'kibana/public';
+import { createSearchSource } from './search_source';
 import { SearchAggsSetup, SearchAggsStart, SearchAggsStartLegacy } from './aggs';
 import { ISearch, ISearchGeneric } from './i_search';
 import { TStrategyTypes } from './strategy_types';
@@ -89,5 +90,6 @@ export interface ISearchStart {
   aggs: SearchAggsStart;
   setInterceptor: (searchInterceptor: SearchInterceptor) => void;
   search: ISearchGeneric;
+  createSearchSource: ReturnType<typeof createSearchSource>;
   __LEGACY: ISearchStartLegacy & SearchAggsStartLegacy;
 }
diff --git a/src/plugins/saved_objects/public/plugin.ts b/src/plugins/saved_objects/public/plugin.ts
index 0f5773c00283e..7927238e12066 100644
--- a/src/plugins/saved_objects/public/plugin.ts
+++ b/src/plugins/saved_objects/public/plugin.ts
@@ -39,6 +39,7 @@ export class SavedObjectsPublicPlugin
       SavedObjectClass: createSavedObjectClass({
         indexPatterns: data.indexPatterns,
         savedObjectsClient: core.savedObjects.client,
+        search: data.search,
         chrome: core.chrome,
         overlays: core.overlays,
       }),
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts b/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts
index 2e965eaf1989b..9776887b6d741 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts
@@ -18,9 +18,8 @@
  */
 import _ from 'lodash';
 import { EsResponse, SavedObject, SavedObjectConfig } from '../../types';
-import { parseSearchSource } from './parse_search_source';
 import { expandShorthand, SavedObjectNotFound } from '../../../../kibana_utils/public';
-import { IndexPattern } from '../../../../data/public';
+import { DataPublicPluginStart, IndexPattern } from '../../../../data/public';
 
 /**
  * A given response of and ElasticSearch containing a plain saved object is applied to the given
@@ -29,13 +28,13 @@ import { IndexPattern } from '../../../../data/public';
 export async function applyESResp(
   resp: EsResponse,
   savedObject: SavedObject,
-  config: SavedObjectConfig
+  config: SavedObjectConfig,
+  createSearchSource: DataPublicPluginStart['search']['createSearchSource']
 ) {
   const mapping = expandShorthand(config.mapping);
   const esType = config.type || '';
   savedObject._source = _.cloneDeep(resp._source);
   const injectReferences = config.injectReferences;
-  const hydrateIndexPattern = savedObject.hydrateIndexPattern!;
   if (typeof resp.found === 'boolean' && !resp.found) {
     throw new SavedObjectNotFound(esType, savedObject.id || '');
   }
@@ -64,13 +63,34 @@ export async function applyESResp(
   _.assign(savedObject, savedObject._source);
   savedObject.lastSavedTitle = savedObject.title;
 
-  await parseSearchSource(savedObject, esType, meta.searchSourceJSON, resp.references);
-  await hydrateIndexPattern();
+  if (config.searchSource) {
+    try {
+      savedObject.searchSource = await createSearchSource(meta.searchSourceJSON, resp.references);
+    } catch (error) {
+      if (
+        error.constructor.name === 'SavedObjectNotFound' &&
+        error.savedObjectType === 'index-pattern'
+      ) {
+        // if parsing the search source fails because the index pattern wasn't found,
+        // remember the reference - this is required for error handling on legacy imports
+        savedObject.unresolvedIndexPatternReference = {
+          name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+          id: JSON.parse(meta.searchSourceJSON).index,
+          type: 'index-pattern',
+        };
+      }
+
+      throw error;
+    }
+  }
+
   if (injectReferences && resp.references && resp.references.length > 0) {
     injectReferences(savedObject, resp.references);
   }
+
   if (typeof config.afterESResp === 'function') {
     savedObject = await config.afterESResp(savedObject);
   }
+
   return savedObject;
 }
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts b/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts
index b9043890e2775..e8faef4e9e040 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts
@@ -81,7 +81,8 @@ export function buildSavedObject(
    */
   savedObject.init = _.once(() => intializeSavedObject(savedObject, savedObjectsClient, config));
 
-  savedObject.applyESResp = (resp: EsResponse) => applyESResp(resp, savedObject, config);
+  savedObject.applyESResp = (resp: EsResponse) =>
+    applyESResp(resp, savedObject, config, services.search.createSearchSource);
 
   /**
    * Serialize this object
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/hydrate_index_pattern.ts b/src/plugins/saved_objects/public/saved_object/helpers/hydrate_index_pattern.ts
index b55538e4073ba..84275cf35befb 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/hydrate_index_pattern.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/hydrate_index_pattern.ts
@@ -31,25 +31,19 @@ export async function hydrateIndexPattern(
   indexPatterns: IndexPatternsContract,
   config: SavedObjectConfig
 ) {
-  const clearSavedIndexPattern = !!config.clearSavedIndexPattern;
   const indexPattern = config.indexPattern;
 
   if (!savedObject.searchSource) {
     return null;
   }
 
-  if (clearSavedIndexPattern) {
-    savedObject.searchSource!.setField('index', undefined);
-    return null;
-  }
-
-  const index = id || indexPattern || savedObject.searchSource!.getOwnField('index');
+  const index = id || indexPattern || savedObject.searchSource.getOwnField('index');
 
   if (typeof index !== 'string' || !index) {
     return null;
   }
 
   const indexObj = await indexPatterns.get(index);
-  savedObject.searchSource!.setField('index', indexObj);
+  savedObject.searchSource.setField('index', indexObj);
   return indexObj;
 }
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/parse_search_source.ts b/src/plugins/saved_objects/public/saved_object/helpers/parse_search_source.ts
deleted file mode 100644
index cdb191f9e7df8..0000000000000
--- a/src/plugins/saved_objects/public/saved_object/helpers/parse_search_source.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import _ from 'lodash';
-import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
-import { SavedObject } from '../../types';
-import { InvalidJSONProperty } from '../../../../kibana_utils/public';
-
-export function parseSearchSource(
-  savedObject: SavedObject,
-  esType: string,
-  searchSourceJson: string,
-  references: any[]
-) {
-  if (!savedObject.searchSource) return;
-
-  // if we have a searchSource, set its values based on the searchSourceJson field
-  let searchSourceValues: Record<string, any>;
-  try {
-    searchSourceValues = JSON.parse(searchSourceJson);
-  } catch (e) {
-    throw new InvalidJSONProperty(
-      `Invalid JSON in ${esType} "${savedObject.id}". ${e.message} JSON: ${searchSourceJson}`
-    );
-  }
-
-  // This detects a scenario where documents with invalid JSON properties have been imported into the saved object index.
-  // (This happened in issue #20308)
-  if (!searchSourceValues || typeof searchSourceValues !== 'object') {
-    throw new InvalidJSONProperty(`Invalid searchSourceJSON in ${esType} "${savedObject.id}".`);
-  }
-
-  // Inject index id if a reference is saved
-  if (searchSourceValues.indexRefName) {
-    const reference = references.find(
-      (ref: Record<string, any>) => ref.name === searchSourceValues.indexRefName
-    );
-    if (!reference) {
-      throw new Error(
-        `Could not find reference for ${
-          searchSourceValues.indexRefName
-        } on ${savedObject.getEsType()} ${savedObject.id}`
-      );
-    }
-    searchSourceValues.index = reference.id;
-    delete searchSourceValues.indexRefName;
-  }
-
-  if (searchSourceValues.filter) {
-    searchSourceValues.filter.forEach((filterRow: any) => {
-      if (!filterRow.meta || !filterRow.meta.indexRefName) {
-        return;
-      }
-      const reference = references.find((ref: any) => ref.name === filterRow.meta.indexRefName);
-      if (!reference) {
-        throw new Error(
-          `Could not find reference for ${
-            filterRow.meta.indexRefName
-          } on ${savedObject.getEsType()}`
-        );
-      }
-      filterRow.meta.index = reference.id;
-      delete filterRow.meta.indexRefName;
-    });
-  }
-
-  const searchSourceFields = savedObject.searchSource.getFields();
-  const fnProps = _.transform(
-    searchSourceFields,
-    function(dynamic: Record<string, any>, val: any, name: string | undefined) {
-      if (_.isFunction(val) && name) dynamic[name] = val;
-    },
-    {}
-  );
-
-  savedObject.searchSource.setFields(_.defaults(searchSourceValues, fnProps));
-  const query = savedObject.searchSource.getOwnField('query');
-
-  if (typeof query !== 'undefined') {
-    savedObject.searchSource.setField('query', migrateLegacyQuery(query));
-  }
-}
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts b/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts
index 8a020ca03aea3..78f9eeb8b5fb1 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts
@@ -17,7 +17,6 @@
  * under the License.
  */
 import _ from 'lodash';
-import angular from 'angular';
 import { SavedObject, SavedObjectConfig } from '../../types';
 import { expandShorthand } from '../../../../kibana_utils/public';
 
@@ -41,57 +40,16 @@ export function serializeSavedObject(savedObject: SavedObject, config: SavedObje
   });
 
   if (savedObject.searchSource) {
-    let searchSourceFields: Record<string, any> = _.omit(savedObject.searchSource.getFields(), [
-      'sort',
-      'size',
-    ]);
-    if (searchSourceFields.index) {
-      // searchSourceFields.index will normally be an IndexPattern, but can be a string in two scenarios:
-      // (1) `init()` (and by extension `hydrateIndexPattern()`) hasn't been called on  Saved Object
-      // (2) The IndexPattern doesn't exist, so we fail to resolve it in `hydrateIndexPattern()`
-      const indexId =
-        typeof searchSourceFields.index === 'string'
-          ? searchSourceFields.index
-          : searchSourceFields.index.id;
-      const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
-      references.push({
-        name: refName,
-        type: 'index-pattern',
-        id: indexId,
-      });
-      searchSourceFields = {
-        ...searchSourceFields,
-        indexRefName: refName,
-        index: undefined,
-      };
-    }
-    if (searchSourceFields.filter) {
-      searchSourceFields = {
-        ...searchSourceFields,
-        filter: searchSourceFields.filter.map((filterRow: any, i: number) => {
-          if (!filterRow.meta || !filterRow.meta.index) {
-            return filterRow;
-          }
-          const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`;
-          references.push({
-            name: refName,
-            type: 'index-pattern',
-            id: filterRow.meta.index,
-          });
-          return {
-            ...filterRow,
-            meta: {
-              ...filterRow.meta,
-              indexRefName: refName,
-              index: undefined,
-            },
-          };
-        }),
-      };
-    }
-    attributes.kibanaSavedObjectMeta = {
-      searchSourceJSON: angular.toJson(searchSourceFields),
-    };
+    const {
+      searchSourceJSON,
+      references: searchSourceReferences,
+    } = savedObject.searchSource.serialize();
+    attributes.kibanaSavedObjectMeta = { searchSourceJSON };
+    references.push(...searchSourceReferences);
+  }
+
+  if (savedObject.unresolvedIndexPatternReference) {
+    references.push(savedObject.unresolvedIndexPatternReference);
   }
 
   return { attributes, references };
diff --git a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts
index 08389e9e3c97f..60c66f84080b2 100644
--- a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts
+++ b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts
@@ -103,9 +103,11 @@ describe('Saved Object', () => {
   }
 
   beforeEach(() => {
+    (dataStartMock.search.createSearchSource as jest.Mock).mockReset();
     SavedObjectClass = createSavedObjectClass({
       savedObjectsClient: savedObjectsClientStub,
       indexPatterns: dataStartMock.indexPatterns,
+      search: dataStartMock.search,
     } as SavedObjectKibanaServices);
   });
 
@@ -269,7 +271,7 @@ describe('Saved Object', () => {
         );
       });
 
-      it('when index exists in searchSourceJSON', () => {
+      it('when search source references saved object', () => {
         const id = '123';
         stubESResponse(getMockedDocResponse(id));
         return createInitializedSavedObject({ type: 'dashboard', searchSource: true }).then(
@@ -409,18 +411,17 @@ describe('Saved Object', () => {
       });
     });
 
-    it('throws error invalid JSON is detected', async () => {
+    it('forwards thrown exceptions from createSearchSource', async () => {
+      (dataStartMock.search.createSearchSource as jest.Mock).mockImplementation(() => {
+        throw new InvalidJSONProperty('');
+      });
       const savedObject = await createInitializedSavedObject({
         type: 'dashboard',
         searchSource: true,
       });
       const response = {
         found: true,
-        _source: {
-          kibanaSavedObjectMeta: {
-            searchSourceJSON: '"{\\n  \\"filter\\": []\\n}"',
-          },
-        },
+        _source: {},
       };
 
       try {
@@ -586,23 +587,24 @@ describe('Saved Object', () => {
         });
     });
 
-    it('injects references from searchSourceJSON', async () => {
+    it('passes references to search source parsing function', async () => {
       const savedObject = new SavedObjectClass({ type: 'dashboard', searchSource: true });
       return savedObject.init!().then(() => {
+        const searchSourceJSON = JSON.stringify({
+          indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+          filter: [
+            {
+              meta: {
+                indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+              },
+            },
+          ],
+        });
         const response = {
           found: true,
           _source: {
             kibanaSavedObjectMeta: {
-              searchSourceJSON: JSON.stringify({
-                indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
-                filter: [
-                  {
-                    meta: {
-                      indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
-                    },
-                  },
-                ],
-              }),
+              searchSourceJSON,
             },
           },
           references: [
@@ -619,16 +621,10 @@ describe('Saved Object', () => {
           ],
         };
         savedObject.applyESResp(response);
-        expect(savedObject.searchSource!.getFields()).toEqual({
-          index: 'my-index-1',
-          filter: [
-            {
-              meta: {
-                index: 'my-index-2',
-              },
-            },
-          ],
-        });
+        expect(dataStartMock.search.createSearchSource).toBeCalledWith(
+          searchSourceJSON,
+          response.references
+        );
       });
     });
   });
diff --git a/src/plugins/saved_objects/public/types.ts b/src/plugins/saved_objects/public/types.ts
index 99088df84ec36..3184038040952 100644
--- a/src/plugins/saved_objects/public/types.ts
+++ b/src/plugins/saved_objects/public/types.ts
@@ -24,7 +24,12 @@ import {
   SavedObjectAttributes,
   SavedObjectReference,
 } from 'kibana/public';
-import { IIndexPattern, IndexPatternsContract, ISearchSource } from '../../data/public';
+import {
+  DataPublicPluginStart,
+  IIndexPattern,
+  IndexPatternsContract,
+  ISearchSource,
+} from '../../data/public';
 
 export interface SavedObject {
   _serialize: () => { attributes: SavedObjectAttributes; references: SavedObjectReference[] };
@@ -49,6 +54,7 @@ export interface SavedObject {
   searchSource?: ISearchSource;
   showInRecentlyAccessed: boolean;
   title: string;
+  unresolvedIndexPatternReference?: SavedObjectReference;
 }
 
 export interface SavedObjectSaveOpts {
@@ -65,6 +71,7 @@ export interface SavedObjectCreationOpts {
 export interface SavedObjectKibanaServices {
   savedObjectsClient: SavedObjectsClientContract;
   indexPatterns: IndexPatternsContract;
+  search: DataPublicPluginStart['search'];
   chrome: ChromeStart;
   overlays: OverlayStart;
 }
@@ -72,7 +79,6 @@ export interface SavedObjectKibanaServices {
 export interface SavedObjectConfig {
   // is only used by visualize
   afterESResp?: (savedObject: SavedObject) => Promise<SavedObject>;
-  clearSavedIndexPattern?: boolean;
   defaults?: any;
   extractReferences?: (opts: {
     attributes: SavedObjectAttributes;
diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts
index 216defcee9016..8fcb84b19a9be 100644
--- a/src/plugins/visualizations/public/plugin.ts
+++ b/src/plugins/visualizations/public/plugin.ts
@@ -26,6 +26,7 @@ import {
   setCapabilities,
   setHttp,
   setIndexPatterns,
+  setSearch,
   setSavedObjects,
   setUsageCollector,
   setFilterManager,
@@ -140,6 +141,7 @@ export class VisualizationsPlugin
     setHttp(core.http);
     setSavedObjects(core.savedObjects);
     setIndexPatterns(data.indexPatterns);
+    setSearch(data.search);
     setFilterManager(data.query.filterManager);
     setExpressions(expressions);
     setUiActions(uiActions);
@@ -150,6 +152,7 @@ export class VisualizationsPlugin
     const savedVisualizationsLoader = createSavedVisLoader({
       savedObjectsClient: core.savedObjects.client,
       indexPatterns: data.indexPatterns,
+      search: data.search,
       chrome: core.chrome,
       overlays: core.overlays,
       visualizationTypes: types,
diff --git a/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts b/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts
index bc96e08f4b9da..c99c7a4c2caa1 100644
--- a/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts
+++ b/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts
@@ -35,7 +35,7 @@ import { extractReferences, injectReferences } from './saved_visualization_refer
 import { IIndexPattern, ISearchSource, SearchSource } from '../../../../plugins/data/public';
 import { ISavedVis, SerializedVis } from '../types';
 import { createSavedSearchesLoader } from '../../../../plugins/discover/public';
-import { getChrome, getOverlays, getIndexPatterns, getSavedObjects } from '../services';
+import { getChrome, getOverlays, getIndexPatterns, getSavedObjects, getSearch } from '../services';
 
 export const convertToSerializedVis = async (savedVis: ISavedVis): Promise<SerializedVis> => {
   const { visState } = savedVis;
@@ -87,6 +87,7 @@ const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?:
     const savedSearch = await createSavedSearchesLoader({
       savedObjectsClient: getSavedObjects().client,
       indexPatterns: getIndexPatterns(),
+      search: getSearch(),
       chrome: getChrome(),
       overlays: getOverlays(),
     }).get(savedSearchId);
diff --git a/src/plugins/visualizations/public/services.ts b/src/plugins/visualizations/public/services.ts
index c4668fa4b0c79..618c61dff176a 100644
--- a/src/plugins/visualizations/public/services.ts
+++ b/src/plugins/visualizations/public/services.ts
@@ -63,6 +63,8 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatt
   'IndexPatterns'
 );
 
+export const [getSearch, setSearch] = createGetterSetter<DataPublicPluginStart['search']>('Search');
+
 export const [getUsageCollector, setUsageCollector] = createGetterSetter<UsageCollectionSetup>(
   'UsageCollection'
 );
diff --git a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js b/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js
index 252d602e8f564..bc636c0b200f8 100644
--- a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js
+++ b/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js
@@ -17,6 +17,7 @@ module.service('gisMapSavedObjectLoader', function() {
   const services = {
     savedObjectsClient,
     indexPatterns: npStart.plugins.data.indexPatterns,
+    search: npStart.plugins.data.search,
     chrome: npStart.core.chrome,
     overlays: npStart.core.overlays,
   };
diff --git a/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts b/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts
index f5f9e98fe659c..feff17b813112 100644
--- a/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts
+++ b/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts
@@ -29,6 +29,7 @@ export const useSearchItems = (defaultSavedObjectId: string | undefined) => {
   const savedSearches = createSavedSearchesLoader({
     savedObjectsClient,
     indexPatterns,
+    search: appDeps.data.search,
     chrome: appDeps.chrome,
     overlays: appDeps.overlays,
   });

From 2a1c8d8de477f3aa94f010a8919ed8b9fb266117 Mon Sep 17 00:00:00 2001
From: Matthias Wilhelm <ankertal@gmail.com>
Date: Thu, 9 Apr 2020 14:30:21 +0200
Subject: [PATCH 15/78] [Discover] Hide time picker when an indexpattern
 without timefield is selected (#62134)

* Assign valid value whether the timepicker should be displayed

* Add functional tests
---
 .../discover/np_ready/angular/discover.html   |  2 +-
 .../_indexpattern_without_timefield.ts        | 52 +++++++++++++++
 test/functional/apps/discover/index.js        |  1 +
 .../index_pattern_without_timefield/data.json | 65 +++++++++++++++++++
 .../mappings.json                             | 39 +++++++++++
 5 files changed, 158 insertions(+), 1 deletion(-)
 create mode 100644 test/functional/apps/discover/_indexpattern_without_timefield.ts
 create mode 100644 test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json
 create mode 100644 test/functional/fixtures/es_archiver/index_pattern_without_timefield/mappings.json

diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html
index fb38f3e7d4c49..d068e824a3e0a 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html
@@ -11,7 +11,7 @@ <h1 class="euiScreenReaderOnly">{{screenTitle}}</h1>
     query="state.query"
     saved-query-id="state.savedQuery"
     screen-title="screenTitle"
-    show-date-picker="enableTimeRangeSelector"
+    show-date-picker="indexPattern.isTimeBased()"
     show-save-query="showSaveQuery"
     show-search-bar="true"
     use-default-behaviors="true"
diff --git a/test/functional/apps/discover/_indexpattern_without_timefield.ts b/test/functional/apps/discover/_indexpattern_without_timefield.ts
new file mode 100644
index 0000000000000..87a2da7e44a5e
--- /dev/null
+++ b/test/functional/apps/discover/_indexpattern_without_timefield.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 { FtrProviderContext } from '../../ftr_provider_context';
+
+export default function({ getService, getPageObjects }: FtrProviderContext) {
+  const esArchiver = getService('esArchiver');
+  const PageObjects = getPageObjects(['common', 'timePicker', 'discover']);
+
+  describe('indexpattern without timefield', function() {
+    before(async function() {
+      await esArchiver.loadIfNeeded('index_pattern_without_timefield');
+    });
+
+    beforeEach(async function() {
+      await PageObjects.common.navigateToApp('discover');
+      await PageObjects.discover.selectIndexPattern('without-timefield');
+    });
+
+    after(async function unloadMakelogs() {
+      await esArchiver.unload('index_pattern_without_timefield');
+    });
+
+    it('should not display a timepicker', async function() {
+      const timepickerExists = await PageObjects.timePicker.timePickerExists();
+      expect(timepickerExists).to.be(false);
+    });
+
+    it('should display a timepicker after switching to an index pattern with timefield', async function() {
+      expect(await PageObjects.timePicker.timePickerExists()).to.be(false);
+      await PageObjects.discover.selectIndexPattern('with-timefield');
+      expect(await PageObjects.timePicker.timePickerExists()).to.be(true);
+    });
+  });
+}
diff --git a/test/functional/apps/discover/index.js b/test/functional/apps/discover/index.js
index 582c979a194f4..50f140b99aa1a 100644
--- a/test/functional/apps/discover/index.js
+++ b/test/functional/apps/discover/index.js
@@ -47,5 +47,6 @@ export default function({ getService, loadTestFile }) {
     loadTestFile(require.resolve('./_doc_navigation'));
     loadTestFile(require.resolve('./_date_nanos'));
     loadTestFile(require.resolve('./_date_nanos_mixed'));
+    loadTestFile(require.resolve('./_indexpattern_without_timefield'));
   });
 }
diff --git a/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json
new file mode 100644
index 0000000000000..9493408a30040
--- /dev/null
+++ b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json
@@ -0,0 +1,65 @@
+{
+  "type": "doc",
+  "value": {
+    "id": "index-pattern:without-timefield",
+    "index": ".kibana",
+    "source": {
+      "index-pattern": {
+        "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]",
+        "title": "without-timefield"
+      },
+      "type": "index-pattern"
+    }
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "AU_x3-TaGFA8no6QjiSJ",
+    "index": "without-timefield",
+    "source": {
+      "@message" : "5",
+      "@timestamp": "2019-09-22T23:50:13.253Z",
+      "referer": "http://twitter.com/error/takuya-onishi",
+      "request": "/uploads/dafydd-williams.jpg",
+      "response": "200",
+      "type": "apache",
+      "url": "https://media-for-the-masses.theacademyofperformingartsandscience.org/uploads/dafydd-williams.jpg"
+    }
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "index-pattern:with-timefield",
+    "index": ".kibana",
+    "source": {
+      "index-pattern": {
+        "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]",
+        "title": "with-timefield",
+        "timeFieldName": "@timestamp"
+      },
+      "type": "index-pattern"
+    }
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "AU_x3-TaGFA8no6QjiSJ",
+    "index": "with-timefield",
+    "source": {
+      "@message" : "5",
+      "@timestamp": "2019-09-22T23:50:13.253Z",
+      "referer": "http://twitter.com/error/takuya-onishi",
+      "request": "/uploads/dafydd-williams.jpg",
+      "response": "200",
+      "type": "apache",
+      "url": "https://media-for-the-masses.theacademyofperformingartsandscience.org/uploads/dafydd-williams.jpg"
+    }
+  }
+}
+
diff --git a/test/functional/fixtures/es_archiver/index_pattern_without_timefield/mappings.json b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/mappings.json
new file mode 100644
index 0000000000000..0096111923951
--- /dev/null
+++ b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/mappings.json
@@ -0,0 +1,39 @@
+{
+  "type": "index",
+  "value": {
+    "index": "without-timefield",
+    "mappings": {
+      "properties": {
+        "@timestamp": {
+          "type": "date"
+        }
+      }
+    },
+    "settings": {
+      "index": {
+        "number_of_replicas": "0",
+        "number_of_shards": "1"
+      }
+    }
+  }
+}
+
+{
+  "type": "index",
+  "value": {
+    "index": "with-timefield",
+    "mappings": {
+      "properties": {
+        "@timestamp": {
+          "type": "date"
+        }
+      }
+    },
+    "settings": {
+      "index": {
+        "number_of_replicas": "0",
+        "number_of_shards": "1"
+      }
+    }
+  }
+}

From 883af7008934bc7d9bf26fc7c5663ff6a2ab8355 Mon Sep 17 00:00:00 2001
From: Alison Goryachev <alison.goryachev@elastic.co>
Date: Thu, 9 Apr 2020 09:39:33 -0400
Subject: [PATCH 16/78] [Remote clusters] Fix flaky jest tests (#58768)

---
 .../remote_clusters_add.test.js               |  2 -
 .../remote_clusters_edit.test.js              | 44 ++++++++-----------
 .../remote_clusters_list.test.js              | 18 ++++----
 .../remote_cluster_form.test.js.snap          |  6 ++-
 .../remote_cluster_form.js                    |  2 +-
 .../remote_cluster_add/remote_cluster_add.js  |  6 ++-
 6 files changed, 40 insertions(+), 38 deletions(-)

diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js
index 78482198b1a5d..569c9a6c56c5a 100644
--- a/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js
+++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js
@@ -7,8 +7,6 @@
 import { pageHelpers, nextTick, setupEnvironment } from './helpers';
 import { NON_ALPHA_NUMERIC_CHARS, ACCENTED_CHARS } from './helpers/constants';
 
-jest.mock('ui/new_platform');
-
 const { setup } = pageHelpers.remoteClustersAdd;
 
 describe('Create Remote cluster', () => {
diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js
index f7625d9eec090..a5905227f49b8 100644
--- a/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js
+++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js
@@ -4,29 +4,22 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-jest.mock('ui/new_platform');
+import { act } from 'react-dom/test-utils';
+
 import { RemoteClusterForm } from '../../public/application/sections/components/remote_cluster_form';
-// import { pageHelpers, setupEnvironment, nextTick } from './helpers';
-import { pageHelpers, nextTick } from './helpers';
+import { pageHelpers, setupEnvironment } from './helpers';
 import { REMOTE_CLUSTER_EDIT, REMOTE_CLUSTER_EDIT_NAME } from './helpers/constants';
 
-// const { setup } = pageHelpers.remoteClustersEdit;
+const { setup } = pageHelpers.remoteClustersEdit;
 const { setup: setupRemoteClustersAdd } = pageHelpers.remoteClustersAdd;
 
-// FLAKY: https://github.com/elastic/kibana/issues/57762
-// FLAKY: https://github.com/elastic/kibana/issues/57997
-// FLAKY: https://github.com/elastic/kibana/issues/57998
-describe.skip('Edit Remote cluster', () => {
-  // let server;
-  // let httpRequestsMockHelpers;
+describe('Edit Remote cluster', () => {
+  let server;
+  let httpRequestsMockHelpers;
   let component;
   let find;
   let exists;
-
-  /**
-   *
-   * commented out due to hooks being called regardless of skip
-   * https://github.com/facebook/jest/issues/8379
+  let waitFor;
 
   beforeAll(() => {
     ({ server, httpRequestsMockHelpers } = setupEnvironment());
@@ -39,13 +32,12 @@ describe.skip('Edit Remote cluster', () => {
   beforeEach(async () => {
     httpRequestsMockHelpers.setLoadRemoteClustersResponse([REMOTE_CLUSTER_EDIT]);
 
-    ({ component, find, exists } = setup());
-    await nextTick(100); // We need to wait next tick for the mock server response to kick in
-    component.update();
+    await act(async () => {
+      ({ component, find, exists, waitFor } = setup());
+      await waitFor('remoteClusterForm');
+    });
   });
 
-  */
-
   test('should have the title of the page set correctly', () => {
     expect(exists('remoteClusterPageTitle')).toBe(true);
     expect(find('remoteClusterPageTitle').text()).toEqual('Edit remote cluster');
@@ -60,14 +52,16 @@ describe.skip('Edit Remote cluster', () => {
    * the "create" remote cluster, we won't test it again but simply make sure that
    * the form component is indeed shared between the 2 app sections.
    */
-  test('should use the same Form component as the "<RemoteClusterEdit />" component', async () => {
-    const { component: addRemoteClusterComponent } = setupRemoteClustersAdd();
+  test('should use the same Form component as the "<RemoteClusterAdd />" component', async () => {
+    let addRemoteClusterTestBed;
 
-    await nextTick();
-    addRemoteClusterComponent.update();
+    await act(async () => {
+      addRemoteClusterTestBed = setupRemoteClustersAdd();
+      addRemoteClusterTestBed.waitFor('remoteClusterAddPage');
+    });
 
     const formEdit = component.find(RemoteClusterForm);
-    const formAdd = addRemoteClusterComponent.find(RemoteClusterForm);
+    const formAdd = addRemoteClusterTestBed.component.find(RemoteClusterForm);
 
     expect(formEdit.length).toBe(1);
     expect(formAdd.length).toBe(1);
diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js
index 954deb8b98d3e..bc73387831c9d 100644
--- a/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js
+++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js
@@ -3,6 +3,7 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
+import { act } from 'react-dom/test-utils';
 
 import {
   pageHelpers,
@@ -17,8 +18,6 @@ import { getRemoteClusterMock } from '../../fixtures/remote_cluster';
 
 import { PROXY_MODE } from '../../common/constants';
 
-jest.mock('ui/new_platform');
-
 const { setup } = pageHelpers.remoteClustersList;
 
 describe('<RemoteClusterList />', () => {
@@ -78,6 +77,7 @@ describe('<RemoteClusterList />', () => {
     let actions;
     let tableCellsValues;
     let rows;
+    let waitFor;
 
     // For deterministic tests, we need to make sure that remoteCluster1 comes before remoteCluster2
     // in the table list that is rendered. As the table orders alphabetically by index name
@@ -110,11 +110,11 @@ describe('<RemoteClusterList />', () => {
     beforeEach(async () => {
       httpRequestsMockHelpers.setLoadRemoteClustersResponse(remoteClusters);
 
-      // Mount the component
-      ({ component, find, exists, table, actions } = setup());
+      await act(async () => {
+        ({ component, find, exists, table, actions, waitFor } = setup());
 
-      await nextTick(100); // Make sure that the Http request is fulfilled
-      component.update();
+        await waitFor('remoteClusterListTable');
+      });
 
       // Read the remote clusters list table
       ({ rows, tableCellsValues } = table.getMetaData('remoteClusterListTable'));
@@ -241,8 +241,10 @@ describe('<RemoteClusterList />', () => {
         actions.clickBulkDeleteButton();
         actions.clickConfirmModalDeleteRemoteCluster();
 
-        await nextTick(600); // there is a 500ms timeout in the api action
-        component.update();
+        await act(async () => {
+          await nextTick(600); // there is a 500ms timeout in the api action
+          component.update();
+        });
 
         ({ rows } = table.getMetaData('remoteClusterListTable'));
 
diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap
index 1e6c2c4d289aa..35c566548f158 100644
--- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap
+++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap
@@ -118,9 +118,12 @@ exports[`RemoteClusterForm proxy mode renders correct connection settings when u
   }
   save={[Function]}
 >
-  <EuiForm>
+  <EuiForm
+    data-test-subj="remoteClusterForm"
+  >
     <div
       className="euiForm"
+      data-test-subj="remoteClusterForm"
     >
       <EuiDescribedFormGroup
         description={
@@ -1351,6 +1354,7 @@ exports[`RemoteClusterForm renders untouched state 1`] = `
 Array [
   <div
     class="euiForm"
+    data-test-subj="remoteClusterForm"
   >
     <div
       class="euiDescribedFormGroup euiDescribedFormGroup--fullWidth"
diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js
index a392cc9607784..cff9166f2f30b 100644
--- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js
+++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js
@@ -884,7 +884,7 @@ export class RemoteClusterForm extends Component {
       <Fragment>
         {this.renderSaveErrorFeedback()}
 
-        <EuiForm>
+        <EuiForm data-test-subj="remoteClusterForm">
           <EuiDescribedFormGroup
             title={
               <EuiTitle size="s">
diff --git a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js
index 0531310bd097b..4f9c5dcd38254 100644
--- a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js
+++ b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js
@@ -57,7 +57,11 @@ export class RemoteClusterAdd extends PureComponent {
     const { isAddingCluster, addClusterError } = this.props;
 
     return (
-      <EuiPageContent horizontalPosition="center" className="remoteClusterAddPage">
+      <EuiPageContent
+        horizontalPosition="center"
+        className="remoteClusterAddPage"
+        data-test-subj="remoteClusterAddPage"
+      >
         <RemoteClusterPageTitle
           title={
             <FormattedMessage

From 6b5cbd562fae78188b97ad8435f53fb69a0bfc91 Mon Sep 17 00:00:00 2001
From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com>
Date: Thu, 9 Apr 2020 09:41:38 -0400
Subject: [PATCH 17/78] [Endpoint][EPM] Endpoint depending on ingest manager to
 initialize (#62871)

* Endpoint successfully depending on ingest manager to initialize

* Moving the endpoint functional tests to their own directory to avoid enabling ingest in the base tests

* Removing page objects and other endpoint fields from base functional

* Updating code owners with new functional location

* Pointing resolver tests at endpoint functional tests

* Pointing space tests at the endpoint functional directory

* Adding jest test names
---
 .github/CODEOWNERS                            |  3 +-
 x-pack/plugins/endpoint/kibana.json           |  2 +-
 .../public/applications/endpoint/index.tsx    |  2 +
 .../endpoint/mocks/dependencies_start_mock.ts |  3 ++
 .../applications/endpoint/view/setup.tsx      | 52 +++++++++++++++++++
 x-pack/plugins/endpoint/public/plugin.ts      |  2 +
 .../ingest_manager/common/types/models/epm.ts |  1 +
 x-pack/plugins/ingest_manager/public/index.ts |  2 +
 .../plugins/ingest_manager/public/plugin.ts   | 20 ++++++-
 x-pack/scripts/functional_tests.js            |  2 +
 x-pack/test/functional/config.js              |  5 --
 .../endpoint/alerts/api_feature/mappings.json |  3 +-
 x-pack/test/functional/page_objects/index.ts  |  4 --
 .../apps/endpoint/alerts.ts                   |  0
 .../feature_controls/endpoint_spaces.ts       |  0
 .../apps/endpoint/feature_controls/index.ts   |  0
 .../apps/endpoint/header_nav.ts               |  0
 .../apps/endpoint/host_list.ts                |  0
 .../apps/endpoint/index.ts                    |  0
 .../apps/endpoint/landing_page.ts             |  7 ++-
 .../apps/endpoint/policy_list.ts              |  0
 x-pack/test/functional_endpoint/config.ts     | 37 +++++++++++++
 .../ftr_provider_context.d.ts                 | 12 +++++
 .../page_objects/endpoint_alerts_page.ts      |  0
 .../page_objects/endpoint_page.ts             |  0
 .../functional_endpoint/page_objects/index.ts | 15 ++++++
 .../apps/endpoint/index.ts                    | 14 +++++
 .../apps/endpoint/landing_page.ts             | 22 ++++++++
 .../config.ts                                 | 30 +++++++++++
 .../ftr_provider_context.d.ts                 | 12 +++++
 x-pack/test/plugin_functional/config.ts       |  4 +-
 31 files changed, 238 insertions(+), 16 deletions(-)
 create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/setup.tsx
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/alerts.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/feature_controls/endpoint_spaces.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/feature_controls/index.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/header_nav.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/host_list.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/index.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/landing_page.ts (72%)
 rename x-pack/test/{functional => functional_endpoint}/apps/endpoint/policy_list.ts (100%)
 create mode 100644 x-pack/test/functional_endpoint/config.ts
 create mode 100644 x-pack/test/functional_endpoint/ftr_provider_context.d.ts
 rename x-pack/test/{functional => functional_endpoint}/page_objects/endpoint_alerts_page.ts (100%)
 rename x-pack/test/{functional => functional_endpoint}/page_objects/endpoint_page.ts (100%)
 create mode 100644 x-pack/test/functional_endpoint/page_objects/index.ts
 create mode 100644 x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/index.ts
 create mode 100644 x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/landing_page.ts
 create mode 100644 x-pack/test/functional_endpoint_ingest_failure/config.ts
 create mode 100644 x-pack/test/functional_endpoint_ingest_failure/ftr_provider_context.d.ts

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index feaf47e45fd69..e707250ff3261 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -202,7 +202,8 @@
 # Endpoint
 /x-pack/plugins/endpoint/ @elastic/endpoint-app-team
 /x-pack/test/api_integration/apis/endpoint/ @elastic/endpoint-app-team
-/x-pack/test/functional/apps/endpoint/ @elastic/endpoint-app-team
+/x-pack/test/functional_endpoint/ @elastic/endpoint-app-team
+/x-pack/test/functional_endpoint_ingest_failure/ @elastic/endpoint-app-team
 /x-pack/test/functional/es_archives/endpoint/ @elastic/endpoint-app-team
 
 # SIEM
diff --git a/x-pack/plugins/endpoint/kibana.json b/x-pack/plugins/endpoint/kibana.json
index 5b8bec7777406..4b48c83fb0e7c 100644
--- a/x-pack/plugins/endpoint/kibana.json
+++ b/x-pack/plugins/endpoint/kibana.json
@@ -3,7 +3,7 @@
   "version": "1.0.0",
   "kibanaVersion": "kibana",
   "configPath": ["xpack", "endpoint"],
-  "requiredPlugins": ["features", "embeddable", "data", "dataEnhanced"],
+  "requiredPlugins": ["features", "embeddable", "data", "dataEnhanced", "ingestManager"],
   "server": true,
   "ui": true
 }
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx
index 89a6302351a54..82ac95160519c 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx
@@ -18,6 +18,7 @@ import { PolicyList } from './view/policy';
 import { PolicyDetails } from './view/policy';
 import { HeaderNavigation } from './components/header_nav';
 import { AppRootProvider } from './view/app_root_provider';
+import { Setup } from './view/setup';
 
 /**
  * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle.
@@ -48,6 +49,7 @@ const AppRoot: React.FunctionComponent<RouterProps> = React.memo(
   ({ history, store, coreStart, depsStart }) => {
     return (
       <AppRootProvider store={store} history={history} coreStart={coreStart} depsStart={depsStart}>
+        <Setup ingestManager={depsStart.ingestManager} notifications={coreStart.notifications} />
         <HeaderNavigation />
         <Switch>
           <Route
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/mocks/dependencies_start_mock.ts b/x-pack/plugins/endpoint/public/applications/endpoint/mocks/dependencies_start_mock.ts
index 00cf0bca57e66..d3fc653f4c9ba 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/mocks/dependencies_start_mock.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/mocks/dependencies_start_mock.ts
@@ -4,6 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { IngestManagerStart } from '../../../../../ingest_manager/public';
 import {
   dataPluginMock,
   Start as DataPublicStartMock,
@@ -32,6 +33,7 @@ type DataMock = Omit<DataPublicStartMock, 'indexPatterns' | 'query'> & {
  */
 export interface DepsStartMock {
   data: DataMock;
+  ingestManager: IngestManagerStart;
 }
 
 /**
@@ -54,5 +56,6 @@ export const depsStartMock: () => DepsStartMock = () => {
 
   return {
     data: dataMock,
+    ingestManager: { success: true },
   };
 };
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/setup.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/setup.tsx
new file mode 100644
index 0000000000000..a826e1f30f75d
--- /dev/null
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/setup.tsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import * as React from 'react';
+import { i18n } from '@kbn/i18n';
+import { NotificationsStart } from 'kibana/public';
+import { IngestManagerStart } from '../../../../../ingest_manager/public';
+
+export const Setup: React.FunctionComponent<{
+  ingestManager: IngestManagerStart;
+  notifications: NotificationsStart;
+}> = ({ ingestManager, notifications }) => {
+  React.useEffect(() => {
+    const defaultText = i18n.translate('xpack.endpoint.ingestToastMessage', {
+      defaultMessage: 'Ingest Manager failed during its setup.',
+    });
+
+    const title = i18n.translate('xpack.endpoint.ingestToastTitle', {
+      defaultMessage: 'App failed to initialize',
+    });
+
+    const displayToastWithModal = (text: string) => {
+      const errorText = new Error(defaultText);
+      // we're leveraging the notification's error toast which is usually used for displaying stack traces of an
+      // actually Error. Instead of displaying a stack trace we'll display the more detailed error text when the
+      // user clicks `See the full error` button to see the modal
+      errorText.stack = text;
+      notifications.toasts.addError(errorText, {
+        title,
+      });
+    };
+
+    const displayToast = () => {
+      notifications.toasts.addDanger({
+        title,
+        text: defaultText,
+      });
+    };
+
+    if (!ingestManager.success) {
+      if (ingestManager.error) {
+        displayToastWithModal(ingestManager.error.message);
+      } else {
+        displayToast();
+      }
+    }
+  }, [ingestManager, notifications.toasts]);
+
+  return null;
+};
diff --git a/x-pack/plugins/endpoint/public/plugin.ts b/x-pack/plugins/endpoint/public/plugin.ts
index ee5bbe71ae8aa..9964454add801 100644
--- a/x-pack/plugins/endpoint/public/plugin.ts
+++ b/x-pack/plugins/endpoint/public/plugin.ts
@@ -8,6 +8,7 @@ import { Plugin, CoreSetup, AppMountParameters, CoreStart } from 'kibana/public'
 import { EmbeddableSetup } from 'src/plugins/embeddable/public';
 import { DataPublicPluginStart } from 'src/plugins/data/public';
 import { i18n } from '@kbn/i18n';
+import { IngestManagerStart } from '../../ingest_manager/public';
 import { ResolverEmbeddableFactory } from './embeddables/resolver';
 
 export type EndpointPluginStart = void;
@@ -18,6 +19,7 @@ export interface EndpointPluginSetupDependencies {
 }
 export interface EndpointPluginStartDependencies {
   data: DataPublicPluginStart;
+  ingestManager: IngestManagerStart;
 }
 
 /**
diff --git a/x-pack/plugins/ingest_manager/common/types/models/epm.ts b/x-pack/plugins/ingest_manager/common/types/models/epm.ts
index efa6621001038..5524e7505d74b 100644
--- a/x-pack/plugins/ingest_manager/common/types/models/epm.ts
+++ b/x-pack/plugins/ingest_manager/common/types/models/epm.ts
@@ -252,6 +252,7 @@ export enum IngestAssetType {
 export enum DefaultPackages {
   base = 'base',
   system = 'system',
+  endpoint = 'endpoint',
 }
 
 export interface IndexTemplate {
diff --git a/x-pack/plugins/ingest_manager/public/index.ts b/x-pack/plugins/ingest_manager/public/index.ts
index aa1e0e79e548b..c11ad60dffee4 100644
--- a/x-pack/plugins/ingest_manager/public/index.ts
+++ b/x-pack/plugins/ingest_manager/public/index.ts
@@ -6,6 +6,8 @@
 import { PluginInitializerContext } from 'src/core/public';
 import { IngestManagerPlugin } from './plugin';
 
+export { IngestManagerStart } from './plugin';
+
 export const plugin = (initializerContext: PluginInitializerContext) => {
   return new IngestManagerPlugin(initializerContext);
 };
diff --git a/x-pack/plugins/ingest_manager/public/plugin.ts b/x-pack/plugins/ingest_manager/public/plugin.ts
index d7be1c1f1fe6e..77bba0bb0f990 100644
--- a/x-pack/plugins/ingest_manager/public/plugin.ts
+++ b/x-pack/plugins/ingest_manager/public/plugin.ts
@@ -17,11 +17,20 @@ import { LicensingPluginSetup } from '../../licensing/public';
 import { PLUGIN_ID } from '../common/constants';
 
 import { IngestManagerConfigType } from '../common/types';
+import { setupRouteService } from '../common';
 
 export { IngestManagerConfigType } from '../common/types';
 
 export type IngestManagerSetup = void;
-export type IngestManagerStart = void;
+/**
+ * Describes public IngestManager plugin contract returned at the `start` stage.
+ */
+export interface IngestManagerStart {
+  success: boolean;
+  error?: {
+    message: string;
+  };
+}
 
 export interface IngestManagerSetupDeps {
   licensing: LicensingPluginSetup;
@@ -61,7 +70,14 @@ export class IngestManagerPlugin
     });
   }
 
-  public start(core: CoreStart) {}
+  public async start(core: CoreStart): Promise<IngestManagerStart> {
+    try {
+      const { isInitialized: success } = await core.http.post(setupRouteService.getSetupPath());
+      return { success };
+    } catch (error) {
+      return { success: false, error: { message: error.body?.message || 'Unknown error' } };
+    }
+  }
 
   public stop() {}
 }
diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js
index 7943da07716a1..061c9e4a0d921 100644
--- a/x-pack/scripts/functional_tests.js
+++ b/x-pack/scripts/functional_tests.js
@@ -43,6 +43,8 @@ const onlyNotInCoverageTests = [
   require.resolve('../test/licensing_plugin/config.ts'),
   require.resolve('../test/licensing_plugin/config.public.ts'),
   require.resolve('../test/licensing_plugin/config.legacy.ts'),
+  require.resolve('../test/functional_endpoint_ingest_failure/config.ts'),
+  require.resolve('../test/functional_endpoint/config.ts'),
 ];
 
 require('@kbn/plugin-helpers').babelRegister();
diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js
index cff555feace18..bc9a67da731cc 100644
--- a/x-pack/test/functional/config.js
+++ b/x-pack/test/functional/config.js
@@ -57,7 +57,6 @@ export default async function({ readConfigFile }) {
       resolve(__dirname, './apps/cross_cluster_replication'),
       resolve(__dirname, './apps/remote_clusters'),
       resolve(__dirname, './apps/transform'),
-      resolve(__dirname, './apps/endpoint'),
       // This license_management file must be last because it is destructive.
       resolve(__dirname, './apps/license_management'),
     ],
@@ -88,7 +87,6 @@ export default async function({ readConfigFile }) {
         '--xpack.encryptedSavedObjects.encryptionKey="DkdXazszSCYexXqz4YktBGHCRkV6hyNK"',
         '--telemetry.banner=false',
         '--timelion.ui.enabled=true',
-        '--xpack.endpoint.enabled=true',
       ],
     },
     uiSettings: {
@@ -199,9 +197,6 @@ export default async function({ readConfigFile }) {
         pathname: '/app/kibana/',
         hash: '/management/elasticsearch/transform',
       },
-      endpoint: {
-        pathname: '/app/endpoint',
-      },
     },
 
     // choose where esArchiver should load archives from
diff --git a/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/mappings.json b/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/mappings.json
index 64dc395ab69a4..7068c24a4b26c 100644
--- a/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/mappings.json
+++ b/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/mappings.json
@@ -389,7 +389,8 @@
                   "type": "nested"
                 },
                 "file_extension": {
-                  "type": "long"
+                  "ignore_above": 1024,
+                  "type": "keyword"
                 },
                 "project_file": {
                   "properties": {
diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts
index 07c5719ae53c5..782d57adea770 100644
--- a/x-pack/test/functional/page_objects/index.ts
+++ b/x-pack/test/functional/page_objects/index.ts
@@ -46,8 +46,6 @@ import { LensPageProvider } from './lens_page';
 import { InfraMetricExplorerProvider } from './infra_metric_explorer';
 import { RoleMappingsPageProvider } from './role_mappings_page';
 import { SpaceSelectorPageProvider } from './space_selector_page';
-import { EndpointPageProvider } from './endpoint_page';
-import { EndpointAlertsPageProvider } from './endpoint_alerts_page';
 
 // just like services, PageObjects are defined as a map of
 // names to Providers. Merge in Kibana's or pick specific ones
@@ -81,6 +79,4 @@ export const pageObjects = {
   copySavedObjectsToSpace: CopySavedObjectsToSpacePageProvider,
   lens: LensPageProvider,
   roleMappings: RoleMappingsPageProvider,
-  endpoint: EndpointPageProvider,
-  endpointAlerts: EndpointAlertsPageProvider,
 };
diff --git a/x-pack/test/functional/apps/endpoint/alerts.ts b/x-pack/test/functional_endpoint/apps/endpoint/alerts.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/alerts.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/alerts.ts
diff --git a/x-pack/test/functional/apps/endpoint/feature_controls/endpoint_spaces.ts b/x-pack/test/functional_endpoint/apps/endpoint/feature_controls/endpoint_spaces.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/feature_controls/endpoint_spaces.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/feature_controls/endpoint_spaces.ts
diff --git a/x-pack/test/functional/apps/endpoint/feature_controls/index.ts b/x-pack/test/functional_endpoint/apps/endpoint/feature_controls/index.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/feature_controls/index.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/feature_controls/index.ts
diff --git a/x-pack/test/functional/apps/endpoint/header_nav.ts b/x-pack/test/functional_endpoint/apps/endpoint/header_nav.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/header_nav.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/header_nav.ts
diff --git a/x-pack/test/functional/apps/endpoint/host_list.ts b/x-pack/test/functional_endpoint/apps/endpoint/host_list.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/host_list.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/host_list.ts
diff --git a/x-pack/test/functional/apps/endpoint/index.ts b/x-pack/test/functional_endpoint/apps/endpoint/index.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/index.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/index.ts
diff --git a/x-pack/test/functional/apps/endpoint/landing_page.ts b/x-pack/test/functional_endpoint/apps/endpoint/landing_page.ts
similarity index 72%
rename from x-pack/test/functional/apps/endpoint/landing_page.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/landing_page.ts
index 65af91feae407..b4da4631aa60b 100644
--- a/x-pack/test/functional/apps/endpoint/landing_page.ts
+++ b/x-pack/test/functional_endpoint/apps/endpoint/landing_page.ts
@@ -7,8 +7,9 @@
 import expect from '@kbn/expect';
 import { FtrProviderContext } from '../../ftr_provider_context';
 
-export default ({ getPageObjects }: FtrProviderContext) => {
+export default ({ getPageObjects, getService }: FtrProviderContext) => {
   const pageObjects = getPageObjects(['common', 'endpoint']);
+  const testSubjects = getService('testSubjects');
 
   describe('Endpoint landing page', function() {
     this.tags('ciGroup7');
@@ -20,5 +21,9 @@ export default ({ getPageObjects }: FtrProviderContext) => {
       const welcomeEndpointMessage = await pageObjects.endpoint.welcomeEndpointTitle();
       expect(welcomeEndpointMessage).to.be('Hello World');
     });
+
+    it('Does not display a toast indicating that the ingest manager failed to initialize', async () => {
+      await testSubjects.missingOrFail('euiToastHeader');
+    });
   });
 };
diff --git a/x-pack/test/functional/apps/endpoint/policy_list.ts b/x-pack/test/functional_endpoint/apps/endpoint/policy_list.ts
similarity index 100%
rename from x-pack/test/functional/apps/endpoint/policy_list.ts
rename to x-pack/test/functional_endpoint/apps/endpoint/policy_list.ts
diff --git a/x-pack/test/functional_endpoint/config.ts b/x-pack/test/functional_endpoint/config.ts
new file mode 100644
index 0000000000000..37bf57b67b47e
--- /dev/null
+++ b/x-pack/test/functional_endpoint/config.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { resolve } from 'path';
+import { FtrConfigProviderContext } from '@kbn/test/types/ftr';
+import { pageObjects } from './page_objects';
+
+export default async function({ readConfigFile }: FtrConfigProviderContext) {
+  const xpackFunctionalConfig = await readConfigFile(require.resolve('../functional/config.js'));
+
+  return {
+    ...xpackFunctionalConfig.getAll(),
+    pageObjects,
+    testFiles: [resolve(__dirname, './apps/endpoint')],
+    junit: {
+      reportName: 'X-Pack Endpoint Functional Tests',
+    },
+    apps: {
+      ...xpackFunctionalConfig.get('apps'),
+      endpoint: {
+        pathname: '/app/endpoint',
+      },
+    },
+    kbnTestServer: {
+      ...xpackFunctionalConfig.get('kbnTestServer'),
+      serverArgs: [
+        ...xpackFunctionalConfig.get('kbnTestServer.serverArgs'),
+        '--xpack.endpoint.enabled=true',
+        '--xpack.ingestManager.enabled=true',
+        '--xpack.ingestManager.fleet.enabled=true',
+      ],
+    },
+  };
+}
diff --git a/x-pack/test/functional_endpoint/ftr_provider_context.d.ts b/x-pack/test/functional_endpoint/ftr_provider_context.d.ts
new file mode 100644
index 0000000000000..21ab5d5a4e554
--- /dev/null
+++ b/x-pack/test/functional_endpoint/ftr_provider_context.d.ts
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { GenericFtrProviderContext } from '@kbn/test/types/ftr';
+
+import { pageObjects } from './page_objects';
+import { services } from '../functional/services';
+
+export type FtrProviderContext = GenericFtrProviderContext<typeof services, typeof pageObjects>;
diff --git a/x-pack/test/functional/page_objects/endpoint_alerts_page.ts b/x-pack/test/functional_endpoint/page_objects/endpoint_alerts_page.ts
similarity index 100%
rename from x-pack/test/functional/page_objects/endpoint_alerts_page.ts
rename to x-pack/test/functional_endpoint/page_objects/endpoint_alerts_page.ts
diff --git a/x-pack/test/functional/page_objects/endpoint_page.ts b/x-pack/test/functional_endpoint/page_objects/endpoint_page.ts
similarity index 100%
rename from x-pack/test/functional/page_objects/endpoint_page.ts
rename to x-pack/test/functional_endpoint/page_objects/endpoint_page.ts
diff --git a/x-pack/test/functional_endpoint/page_objects/index.ts b/x-pack/test/functional_endpoint/page_objects/index.ts
new file mode 100644
index 0000000000000..8138ce2eeccb3
--- /dev/null
+++ b/x-pack/test/functional_endpoint/page_objects/index.ts
@@ -0,0 +1,15 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { pageObjects as xpackFunctionalPageObjects } from '../../functional/page_objects';
+import { EndpointPageProvider } from './endpoint_page';
+import { EndpointAlertsPageProvider } from './endpoint_alerts_page';
+
+export const pageObjects = {
+  ...xpackFunctionalPageObjects,
+  endpoint: EndpointPageProvider,
+  endpointAlerts: EndpointAlertsPageProvider,
+};
diff --git a/x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/index.ts b/x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/index.ts
new file mode 100644
index 0000000000000..ae35f3e525461
--- /dev/null
+++ b/x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/index.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import { FtrProviderContext } from '../../ftr_provider_context';
+
+export default function({ loadTestFile }: FtrProviderContext) {
+  describe('endpoint when the ingest manager fails to setup correctly', function() {
+    this.tags('ciGroup7');
+
+    loadTestFile(require.resolve('./landing_page'));
+  });
+}
diff --git a/x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/landing_page.ts b/x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/landing_page.ts
new file mode 100644
index 0000000000000..d29250ca3bed4
--- /dev/null
+++ b/x-pack/test/functional_endpoint_ingest_failure/apps/endpoint/landing_page.ts
@@ -0,0 +1,22 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { FtrProviderContext } from '../../ftr_provider_context';
+
+export default ({ getPageObjects, getService }: FtrProviderContext) => {
+  describe('home page', function() {
+    const pageObjects = getPageObjects(['common']);
+    const testSubjects = getService('testSubjects');
+
+    before(async () => {
+      await pageObjects.common.navigateToApp('endpoint');
+    });
+
+    it('displays an error toast', async () => {
+      await testSubjects.existOrFail('euiToastHeader');
+    });
+  });
+};
diff --git a/x-pack/test/functional_endpoint_ingest_failure/config.ts b/x-pack/test/functional_endpoint_ingest_failure/config.ts
new file mode 100644
index 0000000000000..a2055a4bbdc18
--- /dev/null
+++ b/x-pack/test/functional_endpoint_ingest_failure/config.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { resolve } from 'path';
+import { FtrConfigProviderContext } from '@kbn/test/types/ftr';
+
+export default async function({ readConfigFile }: FtrConfigProviderContext) {
+  const xpackFunctionalConfig = await readConfigFile(
+    require.resolve('../functional_endpoint/config.ts')
+  );
+
+  return {
+    ...xpackFunctionalConfig.getAll(),
+    testFiles: [resolve(__dirname, './apps/endpoint')],
+    junit: {
+      reportName: 'X-Pack Endpoint Without Ingest Functional Tests',
+    },
+    kbnTestServer: {
+      ...xpackFunctionalConfig.get('kbnTestServer'),
+      serverArgs: [
+        ...xpackFunctionalConfig.get('kbnTestServer.serverArgs'),
+        // use a bogus port so the ingest manager setup will fail
+        '--xpack.ingestManager.epm.registryUrl=http://127.0.0.1:12345',
+      ],
+    },
+  };
+}
diff --git a/x-pack/test/functional_endpoint_ingest_failure/ftr_provider_context.d.ts b/x-pack/test/functional_endpoint_ingest_failure/ftr_provider_context.d.ts
new file mode 100644
index 0000000000000..0e4b47471d419
--- /dev/null
+++ b/x-pack/test/functional_endpoint_ingest_failure/ftr_provider_context.d.ts
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { GenericFtrProviderContext } from '@kbn/test/types/ftr';
+
+import { pageObjects } from '../functional_endpoint/page_objects';
+import { services } from '../functional/services';
+
+export type FtrProviderContext = GenericFtrProviderContext<typeof services, typeof pageObjects>;
diff --git a/x-pack/test/plugin_functional/config.ts b/x-pack/test/plugin_functional/config.ts
index 6c3c496da71f6..aa3c9bd24842a 100644
--- a/x-pack/test/plugin_functional/config.ts
+++ b/x-pack/test/plugin_functional/config.ts
@@ -14,7 +14,9 @@ import { pageObjects } from './page_objects';
 
 /* eslint-disable import/no-default-export */
 export default async function({ readConfigFile }: FtrConfigProviderContext) {
-  const xpackFunctionalConfig = await readConfigFile(require.resolve('../functional/config.js'));
+  const xpackFunctionalConfig = await readConfigFile(
+    require.resolve('../functional_endpoint/config.ts')
+  );
 
   // Find all folders in ./plugins since we treat all them as plugin folder
   const allFiles = fs.readdirSync(resolve(__dirname, 'plugins'));

From abe3ccf1cc45213c2991af83e261a12ce19e91d1 Mon Sep 17 00:00:00 2001
From: Daniil Suleiman <31325372+sulemanof@users.noreply.github.com>
Date: Thu, 9 Apr 2020 17:00:45 +0300
Subject: [PATCH 18/78] [Table Vis] Fix visualization overflow (#62630)

* Fix data table vis overflowing

* Change overflow to hidden
---
 src/plugins/vis_default_editor/public/_default.scss | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/plugins/vis_default_editor/public/_default.scss b/src/plugins/vis_default_editor/public/_default.scss
index 985381eeb56a5..2187baea547da 100644
--- a/src/plugins/vis_default_editor/public/_default.scss
+++ b/src/plugins/vis_default_editor/public/_default.scss
@@ -72,6 +72,7 @@
   display: flex;
   flex-basis: 100%;
   flex: 1;
+  overflow: hidden;
 
   @include euiBreakpoint('xs', 's', 'm') {
     // If we are on a small screen we force the visualization to take 100% width.

From f9ba963af90d41b74e8d7dde9981c9a5cee53127 Mon Sep 17 00:00:00 2001
From: Melissa Alvarez <melissa.alvarez@elastic.co>
Date: Thu, 9 Apr 2020 10:33:55 -0400
Subject: [PATCH 19/78] [ML] DF Analytics:  update memory estimate after adding
 exclude fields (#62850)

* update mml estimate when excludes changes

* ensure manually input mml is validated once estimated mml loads
---
 .../create_analytics_form.tsx                 | 24 +++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx
index 0c83dfb6a2346..199100d8b5ab0 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx
+++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx
@@ -55,7 +55,14 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
   const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
   const { setFormState, setEstimatedModelMemoryLimit } = actions;
   const mlContext = useMlContext();
-  const { form, indexPatternsMap, isAdvancedEditorEnabled, isJobCreated, requestMessages } = state;
+  const {
+    estimatedModelMemoryLimit,
+    form,
+    indexPatternsMap,
+    isAdvancedEditorEnabled,
+    isJobCreated,
+    requestMessages,
+  } = state;
 
   const forceInput = useRef<HTMLInputElement | null>(null);
   const firstUpdate = useRef<boolean>(true);
@@ -152,6 +159,9 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
 
   const debouncedGetExplainData = debounce(async () => {
     const shouldUpdateModelMemoryLimit = !firstUpdate.current || !modelMemoryLimit;
+    const shouldUpdateEstimatedMml =
+      !firstUpdate.current || !modelMemoryLimit || estimatedModelMemoryLimit === '';
+
     if (firstUpdate.current) {
       firstUpdate.current = false;
     }
@@ -167,13 +177,12 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
       const jobConfig = getJobConfigFromFormState(form);
       delete jobConfig.dest;
       delete jobConfig.model_memory_limit;
-      delete jobConfig.analyzed_fields;
       const resp: DfAnalyticsExplainResponse = await ml.dataFrameAnalytics.explainDataFrameAnalytics(
         jobConfig
       );
       const expectedMemoryWithoutDisk = resp.memory_estimation?.expected_memory_without_disk;
 
-      if (shouldUpdateModelMemoryLimit) {
+      if (shouldUpdateEstimatedMml) {
         setEstimatedModelMemoryLimit(expectedMemoryWithoutDisk);
       }
 
@@ -340,7 +349,14 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
     return () => {
       debouncedGetExplainData.cancel();
     };
-  }, [jobType, sourceIndex, sourceIndexNameEmpty, dependentVariable, trainingPercent]);
+  }, [
+    jobType,
+    sourceIndex,
+    sourceIndexNameEmpty,
+    dependentVariable,
+    trainingPercent,
+    JSON.stringify(excludes),
+  ]);
 
   // Temp effect to close the context menu popover on Clone button click
   useEffect(() => {

From 90d2b18bc5c4db75311733aea305c87b06d43675 Mon Sep 17 00:00:00 2001
From: Brandon Kobel <brandon.kobel@elastic.co>
Date: Thu, 9 Apr 2020 07:43:36 -0700
Subject: [PATCH 20/78] Add Data - Adding cloud reset password link to cloud
 instructions (#62835)

* Adding cloud reset password link to cloud filebeat instructions

* Auditbeat gets the cool reset password link

* And the other beats instructions get the awesome password reset link

* Changing the i18n id to more closely match the on-prem cloud id

* Changing text for forgot password

* Removing now unused translations

* "Forgot your password" -> "Forgot the password"

* "Elastic Cloud UI" -> "Elastic Cloud"

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../instructions/auditbeat_instructions.ts    | 33 +++----------------
 .../instructions/cloud_instructions.ts        | 31 +++++++++++++++++
 .../instructions/filebeat_instructions.ts     | 33 +++----------------
 .../instructions/functionbeat_instructions.ts | 17 ++--------
 .../instructions/heartbeat_instructions.ts    | 33 +++----------------
 .../instructions/metricbeat_instructions.ts   | 33 +++----------------
 .../instructions/winlogbeat_instructions.ts   |  9 ++---
 x-pack/plugins/cloud/public/plugin.ts         |  5 +--
 x-pack/plugins/cloud/server/config.ts         |  2 ++
 .../translations/translations/ja-JP.json      | 19 -----------
 .../translations/translations/zh-CN.json      | 19 -----------
 11 files changed, 61 insertions(+), 173 deletions(-)
 create mode 100644 src/plugins/home/server/tutorials/instructions/cloud_instructions.ts

diff --git a/src/plugins/home/server/tutorials/instructions/auditbeat_instructions.ts b/src/plugins/home/server/tutorials/instructions/auditbeat_instructions.ts
index 4c85ad3985b3d..2a6cfa0358709 100644
--- a/src/plugins/home/server/tutorials/instructions/auditbeat_instructions.ts
+++ b/src/plugins/home/server/tutorials/instructions/auditbeat_instructions.ts
@@ -22,6 +22,7 @@ import { INSTRUCTION_VARIANT } from '../../../common/instruction_variant';
 import { createTrycloudOption1, createTrycloudOption2 } from './onprem_cloud_instructions';
 import { getSpaceIdForBeatsTutorial } from './get_space_id_for_beats_tutorial';
 import { Platform, TutorialContext } from '../../services/tutorials/lib/tutorials_registry_types';
+import { cloudPasswordAndResetLink } from './cloud_instructions';
 
 export const createAuditbeatInstructions = (context?: TutorialContext) => ({
   INSTALL: {
@@ -305,13 +306,7 @@ export const createAuditbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.auditbeatCloudInstructions.config.osxTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     DEB: {
       title: i18n.translate('home.tutorials.common.auditbeatCloudInstructions.config.debTitle', {
@@ -327,13 +322,7 @@ export const createAuditbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.auditbeatCloudInstructions.config.debTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     RPM: {
       title: i18n.translate('home.tutorials.common.auditbeatCloudInstructions.config.rpmTitle', {
@@ -349,13 +338,7 @@ export const createAuditbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.auditbeatCloudInstructions.config.rpmTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     WINDOWS: {
       title: i18n.translate(
@@ -374,13 +357,7 @@ export const createAuditbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.auditbeatCloudInstructions.config.windowsTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
   },
 });
diff --git a/src/plugins/home/server/tutorials/instructions/cloud_instructions.ts b/src/plugins/home/server/tutorials/instructions/cloud_instructions.ts
new file mode 100644
index 0000000000000..a18e21d2b43dd
--- /dev/null
+++ b/src/plugins/home/server/tutorials/instructions/cloud_instructions.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 { i18n } from '@kbn/i18n';
+
+export const cloudPasswordAndResetLink = i18n.translate(
+  'home.tutorials.common.cloudInstructions.passwordAndResetLink',
+  {
+    defaultMessage:
+      'Where {passwordTemplate} is the password of the `elastic` user.' +
+      `\\{#config.cloud.resetPasswordUrl\\}
+      Forgot the password? [Reset in Elastic Cloud](\\{config.cloud.resetPasswordUrl\\}).
+      \\{/config.cloud.resetPasswordUrl\\}`,
+    values: { passwordTemplate: '`<password>`' },
+  }
+);
diff --git a/src/plugins/home/server/tutorials/instructions/filebeat_instructions.ts b/src/plugins/home/server/tutorials/instructions/filebeat_instructions.ts
index 66efa36ec9bcd..0e99033b2ea69 100644
--- a/src/plugins/home/server/tutorials/instructions/filebeat_instructions.ts
+++ b/src/plugins/home/server/tutorials/instructions/filebeat_instructions.ts
@@ -22,6 +22,7 @@ import { INSTRUCTION_VARIANT } from '../../../common/instruction_variant';
 import { createTrycloudOption1, createTrycloudOption2 } from './onprem_cloud_instructions';
 import { getSpaceIdForBeatsTutorial } from './get_space_id_for_beats_tutorial';
 import { Platform, TutorialContext } from '../../services/tutorials/lib/tutorials_registry_types';
+import { cloudPasswordAndResetLink } from './cloud_instructions';
 
 export const createFilebeatInstructions = (context?: TutorialContext) => ({
   INSTALL: {
@@ -299,13 +300,7 @@ export const createFilebeatCloudInstructions = () => ({
         },
       }),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.filebeatCloudInstructions.config.osxTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     DEB: {
       title: i18n.translate('home.tutorials.common.filebeatCloudInstructions.config.debTitle', {
@@ -318,13 +313,7 @@ export const createFilebeatCloudInstructions = () => ({
         },
       }),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.filebeatCloudInstructions.config.debTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     RPM: {
       title: i18n.translate('home.tutorials.common.filebeatCloudInstructions.config.rpmTitle', {
@@ -337,13 +326,7 @@ export const createFilebeatCloudInstructions = () => ({
         },
       }),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.filebeatCloudInstructions.config.rpmTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     WINDOWS: {
       title: i18n.translate('home.tutorials.common.filebeatCloudInstructions.config.windowsTitle', {
@@ -359,13 +342,7 @@ export const createFilebeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.filebeatCloudInstructions.config.windowsTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
   },
 });
diff --git a/src/plugins/home/server/tutorials/instructions/functionbeat_instructions.ts b/src/plugins/home/server/tutorials/instructions/functionbeat_instructions.ts
index ee13b9c5eefd8..06ff84146b5d8 100644
--- a/src/plugins/home/server/tutorials/instructions/functionbeat_instructions.ts
+++ b/src/plugins/home/server/tutorials/instructions/functionbeat_instructions.ts
@@ -22,6 +22,7 @@ import { INSTRUCTION_VARIANT } from '../../../common/instruction_variant';
 import { createTrycloudOption1, createTrycloudOption2 } from './onprem_cloud_instructions';
 import { getSpaceIdForBeatsTutorial } from './get_space_id_for_beats_tutorial';
 import { Platform, TutorialContext } from '../../services/tutorials/lib/tutorials_registry_types';
+import { cloudPasswordAndResetLink } from './cloud_instructions';
 
 export const createFunctionbeatInstructions = (context?: TutorialContext) => ({
   INSTALL: {
@@ -200,13 +201,7 @@ export const createFunctionbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.functionbeatCloudInstructions.config.osxTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     WINDOWS: {
       title: i18n.translate(
@@ -225,13 +220,7 @@ export const createFunctionbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.functionbeatCloudInstructions.config.windowsTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
   },
 });
diff --git a/src/plugins/home/server/tutorials/instructions/heartbeat_instructions.ts b/src/plugins/home/server/tutorials/instructions/heartbeat_instructions.ts
index 33f5defc0273f..fa5bf5df13b6b 100644
--- a/src/plugins/home/server/tutorials/instructions/heartbeat_instructions.ts
+++ b/src/plugins/home/server/tutorials/instructions/heartbeat_instructions.ts
@@ -22,6 +22,7 @@ import { INSTRUCTION_VARIANT } from '../../../common/instruction_variant';
 import { createTrycloudOption1, createTrycloudOption2 } from './onprem_cloud_instructions';
 import { getSpaceIdForBeatsTutorial } from './get_space_id_for_beats_tutorial';
 import { Platform, TutorialContext } from '../../services/tutorials/lib/tutorials_registry_types';
+import { cloudPasswordAndResetLink } from './cloud_instructions';
 
 export const createHeartbeatInstructions = (context?: TutorialContext) => ({
   INSTALL: {
@@ -280,13 +281,7 @@ export const createHeartbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.heartbeatCloudInstructions.config.osxTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     DEB: {
       title: i18n.translate('home.tutorials.common.heartbeatCloudInstructions.config.debTitle', {
@@ -302,13 +297,7 @@ export const createHeartbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.heartbeatCloudInstructions.config.debTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     RPM: {
       title: i18n.translate('home.tutorials.common.heartbeatCloudInstructions.config.rpmTitle', {
@@ -324,13 +313,7 @@ export const createHeartbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.heartbeatCloudInstructions.config.rpmTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     WINDOWS: {
       title: i18n.translate(
@@ -349,13 +332,7 @@ export const createHeartbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.heartbeatCloudInstructions.config.windowsTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
   },
 });
diff --git a/src/plugins/home/server/tutorials/instructions/metricbeat_instructions.ts b/src/plugins/home/server/tutorials/instructions/metricbeat_instructions.ts
index 9fdc70e0703a4..651405941610f 100644
--- a/src/plugins/home/server/tutorials/instructions/metricbeat_instructions.ts
+++ b/src/plugins/home/server/tutorials/instructions/metricbeat_instructions.ts
@@ -22,6 +22,7 @@ import { INSTRUCTION_VARIANT } from '../../../common/instruction_variant';
 import { createTrycloudOption1, createTrycloudOption2 } from './onprem_cloud_instructions';
 import { getSpaceIdForBeatsTutorial } from './get_space_id_for_beats_tutorial';
 import { TutorialContext } from '../../services/tutorials/lib/tutorials_registry_types';
+import { cloudPasswordAndResetLink } from './cloud_instructions';
 
 export const createMetricbeatInstructions = (context?: TutorialContext) => ({
   INSTALL: {
@@ -295,13 +296,7 @@ export const createMetricbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.metricbeatCloudInstructions.config.osxTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     DEB: {
       title: i18n.translate('home.tutorials.common.metricbeatCloudInstructions.config.debTitle', {
@@ -317,13 +312,7 @@ export const createMetricbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.metricbeatCloudInstructions.config.debTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     RPM: {
       title: i18n.translate('home.tutorials.common.metricbeatCloudInstructions.config.rpmTitle', {
@@ -339,13 +328,7 @@ export const createMetricbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.metricbeatCloudInstructions.config.rpmTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
     WINDOWS: {
       title: i18n.translate(
@@ -364,13 +347,7 @@ export const createMetricbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.metricbeatCloudInstructions.config.windowsTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
   },
 });
diff --git a/src/plugins/home/server/tutorials/instructions/winlogbeat_instructions.ts b/src/plugins/home/server/tutorials/instructions/winlogbeat_instructions.ts
index 9d7d0660d3d6c..27d7822e080a3 100644
--- a/src/plugins/home/server/tutorials/instructions/winlogbeat_instructions.ts
+++ b/src/plugins/home/server/tutorials/instructions/winlogbeat_instructions.ts
@@ -22,6 +22,7 @@ import { INSTRUCTION_VARIANT } from '../../../common/instruction_variant';
 import { createTrycloudOption1, createTrycloudOption2 } from './onprem_cloud_instructions';
 import { getSpaceIdForBeatsTutorial } from './get_space_id_for_beats_tutorial';
 import { TutorialContext } from '../../services/tutorials/lib/tutorials_registry_types';
+import { cloudPasswordAndResetLink } from './cloud_instructions';
 
 export const createWinlogbeatInstructions = (context?: TutorialContext) => ({
   INSTALL: {
@@ -130,13 +131,7 @@ export const createWinlogbeatCloudInstructions = () => ({
         }
       ),
       commands: ['cloud.id: "{config.cloud.id}"', 'cloud.auth: "elastic:<password>"'],
-      textPost: i18n.translate(
-        'home.tutorials.common.winlogbeatCloudInstructions.config.windowsTextPost',
-        {
-          defaultMessage: 'Where {passwordTemplate} is the password of the `elastic` user.',
-          values: { passwordTemplate: '`<password>`' },
-        }
-      ),
+      textPost: cloudPasswordAndResetLink,
     },
   },
 });
diff --git a/x-pack/plugins/cloud/public/plugin.ts b/x-pack/plugins/cloud/public/plugin.ts
index 2b8247066bfc3..62e21392f7110 100644
--- a/x-pack/plugins/cloud/public/plugin.ts
+++ b/x-pack/plugins/cloud/public/plugin.ts
@@ -11,6 +11,7 @@ import { HomePublicPluginSetup } from '../../../../src/plugins/home/public';
 
 interface CloudConfigType {
   id?: string;
+  resetPasswordUrl?: string;
 }
 
 interface CloudSetupDependencies {
@@ -26,13 +27,13 @@ export class CloudPlugin implements Plugin<CloudSetup> {
   constructor(private readonly initializerContext: PluginInitializerContext) {}
 
   public async setup(core: CoreSetup, { home }: CloudSetupDependencies) {
-    const { id } = this.initializerContext.config.get<CloudConfigType>();
+    const { id, resetPasswordUrl } = this.initializerContext.config.get<CloudConfigType>();
     const isCloudEnabled = getIsCloudEnabled(id);
 
     if (home) {
       home.environment.update({ cloud: isCloudEnabled });
       if (isCloudEnabled) {
-        home.tutorials.setVariable('cloud', { id });
+        home.tutorials.setVariable('cloud', { id, resetPasswordUrl });
       }
     }
 
diff --git a/x-pack/plugins/cloud/server/config.ts b/x-pack/plugins/cloud/server/config.ts
index 77e493dc3b7dc..d899b45aebdfe 100644
--- a/x-pack/plugins/cloud/server/config.ts
+++ b/x-pack/plugins/cloud/server/config.ts
@@ -21,6 +21,7 @@ const configSchema = schema.object({
   enabled: schema.boolean({ defaultValue: true }),
   id: schema.maybe(schema.string()),
   apm: schema.maybe(apmConfigSchema),
+  resetPasswordUrl: schema.maybe(schema.string()),
 });
 
 export type CloudConfigType = TypeOf<typeof configSchema>;
@@ -28,6 +29,7 @@ export type CloudConfigType = TypeOf<typeof configSchema>;
 export const config: PluginConfigDescriptor<CloudConfigType> = {
   exposeToBrowser: {
     id: true,
+    resetPasswordUrl: true,
   },
   schema: configSchema,
 };
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index e63e1c8ad2c91..16c4b11bb6a6e 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -1196,16 +1196,12 @@
     "home.tutorials.common.auditbeat.cloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.auditbeat.premCloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.auditbeat.premInstructions.gettingStarted.title": "はじめに",
-    "home.tutorials.common.auditbeatCloudInstructions.config.debTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.auditbeatCloudInstructions.config.debTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.auditbeatCloudInstructions.config.debTitle": "構成を編集する",
-    "home.tutorials.common.auditbeatCloudInstructions.config.osxTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.auditbeatCloudInstructions.config.osxTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.auditbeatCloudInstructions.config.osxTitle": "構成を編集する",
-    "home.tutorials.common.auditbeatCloudInstructions.config.rpmTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.auditbeatCloudInstructions.config.rpmTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.auditbeatCloudInstructions.config.rpmTitle": "構成を編集する",
-    "home.tutorials.common.auditbeatCloudInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.auditbeatCloudInstructions.config.windowsTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.auditbeatCloudInstructions.config.windowsTitle": "構成を編集する",
     "home.tutorials.common.auditbeatInstructions.config.debTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワード、{esUrlTemplate} が Elasticsearch の URL、{kibanaUrlTemplate} が Kibana の URL です。",
@@ -1247,16 +1243,12 @@
     "home.tutorials.common.filebeat.cloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.filebeat.premCloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.filebeat.premInstructions.gettingStarted.title": "はじめに",
-    "home.tutorials.common.filebeatCloudInstructions.config.debTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.filebeatCloudInstructions.config.debTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.filebeatCloudInstructions.config.debTitle": "構成を編集する",
-    "home.tutorials.common.filebeatCloudInstructions.config.osxTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.filebeatCloudInstructions.config.osxTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.filebeatCloudInstructions.config.osxTitle": "構成を編集する",
-    "home.tutorials.common.filebeatCloudInstructions.config.rpmTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.filebeatCloudInstructions.config.rpmTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.filebeatCloudInstructions.config.rpmTitle": "構成を編集する",
-    "home.tutorials.common.filebeatCloudInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.filebeatCloudInstructions.config.windowsTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.filebeatCloudInstructions.config.windowsTitle": "構成を編集する",
     "home.tutorials.common.filebeatEnableInstructions.debTextPost": "「/etc/filebeat/modules.d/{moduleName}.yml」ファイルで設定を変更します。",
@@ -1311,10 +1303,8 @@
     "home.tutorials.common.functionbeatAWSInstructions.textPost": "「<your-access-key>」と「<your-secret-access-key>」がアカウント資格情報、「us-east-1」がご希望の地域です。",
     "home.tutorials.common.functionbeatAWSInstructions.textPre": "環境で AWS アカウント認証情報を設定します。",
     "home.tutorials.common.functionbeatAWSInstructions.title": "AWS 認証情報の設定",
-    "home.tutorials.common.functionbeatCloudInstructions.config.osxTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.functionbeatCloudInstructions.config.osxTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.functionbeatCloudInstructions.config.osxTitle": "構成を編集する",
-    "home.tutorials.common.functionbeatCloudInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.functionbeatCloudInstructions.config.windowsTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.functionbeatCloudInstructions.config.windowsTitle": "構成を編集する",
     "home.tutorials.common.functionbeatEnableOnPremInstructions.defaultTextPost": "「<cloudwatch-log-group>」が投入するロググループの名前で、「<unique-bucket-name>」が Functionbeat デプロイのステージングに使用されるが有効な S3 バケット名です。",
@@ -1345,16 +1335,12 @@
     "home.tutorials.common.heartbeat.cloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.heartbeat.premCloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.heartbeat.premInstructions.gettingStarted.title": "はじめに",
-    "home.tutorials.common.heartbeatCloudInstructions.config.debTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.heartbeatCloudInstructions.config.debTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.heartbeatCloudInstructions.config.debTitle": "構成を編集する",
-    "home.tutorials.common.heartbeatCloudInstructions.config.osxTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.heartbeatCloudInstructions.config.osxTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.heartbeatCloudInstructions.config.osxTitle": "構成を編集する",
-    "home.tutorials.common.heartbeatCloudInstructions.config.rpmTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.heartbeatCloudInstructions.config.rpmTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.heartbeatCloudInstructions.config.rpmTitle": "構成を編集する",
-    "home.tutorials.common.heartbeatCloudInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.heartbeatCloudInstructions.config.windowsTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.heartbeatCloudInstructions.config.windowsTitle": "構成を編集する",
     "home.tutorials.common.heartbeatEnableCloudInstructions.debTextPre": "「heartbeat.yml」ファイルの「heartbeat.monitors」設定を変更します。",
@@ -1414,16 +1400,12 @@
     "home.tutorials.common.metricbeat.cloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.metricbeat.premCloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.metricbeat.premInstructions.gettingStarted.title": "はじめに",
-    "home.tutorials.common.metricbeatCloudInstructions.config.debTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.metricbeatCloudInstructions.config.debTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.metricbeatCloudInstructions.config.debTitle": "構成を編集する",
-    "home.tutorials.common.metricbeatCloudInstructions.config.osxTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.metricbeatCloudInstructions.config.osxTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.metricbeatCloudInstructions.config.osxTitle": "構成を編集する",
-    "home.tutorials.common.metricbeatCloudInstructions.config.rpmTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.metricbeatCloudInstructions.config.rpmTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.metricbeatCloudInstructions.config.rpmTitle": "構成を編集する",
-    "home.tutorials.common.metricbeatCloudInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.metricbeatCloudInstructions.config.windowsTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.metricbeatCloudInstructions.config.windowsTitle": "構成を編集する",
     "home.tutorials.common.metricbeatEnableInstructions.debTextPost": "「/etc/metricbeat/modules.d/{moduleName}.yml」ファイルで設定を変更します。",
@@ -1478,7 +1460,6 @@
     "home.tutorials.common.winlogbeat.cloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.winlogbeat.premCloudInstructions.gettingStarted.title": "はじめに",
     "home.tutorials.common.winlogbeat.premInstructions.gettingStarted.title": "はじめに",
-    "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワードです。",
     "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTextPre": "{path} を変更して Elastic Cloud への接続情報を設定します:",
     "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTitle": "構成を編集する",
     "home.tutorials.common.winlogbeatInstructions.config.windowsTextPost": "{passwordTemplate} が「Elastic」ユーザーのパスワード、{esUrlTemplate} が Elasticsearch の URL、{kibanaUrlTemplate} が Kibana の URL です。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index cc75ceb988d97..c81fad386ac2f 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -1197,16 +1197,12 @@
     "home.tutorials.common.auditbeat.cloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.auditbeat.premCloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.auditbeat.premInstructions.gettingStarted.title": "入门",
-    "home.tutorials.common.auditbeatCloudInstructions.config.debTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.auditbeatCloudInstructions.config.debTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.auditbeatCloudInstructions.config.debTitle": "编辑配置",
-    "home.tutorials.common.auditbeatCloudInstructions.config.osxTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.auditbeatCloudInstructions.config.osxTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.auditbeatCloudInstructions.config.osxTitle": "编辑配置",
-    "home.tutorials.common.auditbeatCloudInstructions.config.rpmTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.auditbeatCloudInstructions.config.rpmTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.auditbeatCloudInstructions.config.rpmTitle": "编辑配置",
-    "home.tutorials.common.auditbeatCloudInstructions.config.windowsTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.auditbeatCloudInstructions.config.windowsTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.auditbeatCloudInstructions.config.windowsTitle": "编辑配置",
     "home.tutorials.common.auditbeatInstructions.config.debTextPost": "其中,{passwordTemplate} 是 `elastic` 用户的密码,{esUrlTemplate} 是 Elasticsearch 的 URL,{kibanaUrlTemplate} 是 Kibana 的 URL。",
@@ -1248,16 +1244,12 @@
     "home.tutorials.common.filebeat.cloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.filebeat.premCloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.filebeat.premInstructions.gettingStarted.title": "入门",
-    "home.tutorials.common.filebeatCloudInstructions.config.debTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.filebeatCloudInstructions.config.debTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.filebeatCloudInstructions.config.debTitle": "编辑配置",
-    "home.tutorials.common.filebeatCloudInstructions.config.osxTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.filebeatCloudInstructions.config.osxTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.filebeatCloudInstructions.config.osxTitle": "编辑配置",
-    "home.tutorials.common.filebeatCloudInstructions.config.rpmTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.filebeatCloudInstructions.config.rpmTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.filebeatCloudInstructions.config.rpmTitle": "编辑配置",
-    "home.tutorials.common.filebeatCloudInstructions.config.windowsTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.filebeatCloudInstructions.config.windowsTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.filebeatCloudInstructions.config.windowsTitle": "编辑配置",
     "home.tutorials.common.filebeatEnableInstructions.debTextPost": "在 `/etc/filebeat/modules.d/{moduleName}.yml` 文件中修改设置。",
@@ -1312,10 +1304,8 @@
     "home.tutorials.common.functionbeatAWSInstructions.textPost": "其中 `<your-access-key>` 和 `<your-secret-access-key>` 是您的帐户凭据,`us-east-1` 是所需的地区。",
     "home.tutorials.common.functionbeatAWSInstructions.textPre": "在环境中设置您的 AWS 帐户凭据:",
     "home.tutorials.common.functionbeatAWSInstructions.title": "设置 AWS 凭据",
-    "home.tutorials.common.functionbeatCloudInstructions.config.osxTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.functionbeatCloudInstructions.config.osxTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.functionbeatCloudInstructions.config.osxTitle": "编辑配置",
-    "home.tutorials.common.functionbeatCloudInstructions.config.windowsTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.functionbeatCloudInstructions.config.windowsTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.functionbeatCloudInstructions.config.windowsTitle": "编辑配置",
     "home.tutorials.common.functionbeatEnableOnPremInstructions.defaultTextPost": "其中 `<cloudwatch-log-group>` 是要采集的日志组名称,`<unique-bucket-name>` 是将用于暂存 Functionbeat 部署的有效 S3 存储桶名称。",
@@ -1346,16 +1336,12 @@
     "home.tutorials.common.heartbeat.cloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.heartbeat.premCloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.heartbeat.premInstructions.gettingStarted.title": "入门",
-    "home.tutorials.common.heartbeatCloudInstructions.config.debTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.heartbeatCloudInstructions.config.debTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.heartbeatCloudInstructions.config.debTitle": "编辑配置",
-    "home.tutorials.common.heartbeatCloudInstructions.config.osxTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.heartbeatCloudInstructions.config.osxTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.heartbeatCloudInstructions.config.osxTitle": "编辑配置",
-    "home.tutorials.common.heartbeatCloudInstructions.config.rpmTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.heartbeatCloudInstructions.config.rpmTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.heartbeatCloudInstructions.config.rpmTitle": "编辑配置",
-    "home.tutorials.common.heartbeatCloudInstructions.config.windowsTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.heartbeatCloudInstructions.config.windowsTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.heartbeatCloudInstructions.config.windowsTitle": "编辑配置",
     "home.tutorials.common.heartbeatEnableCloudInstructions.debTextPre": "在 `heartbeat.yml` 文件中编辑 `heartbeat.monitors` 设置。",
@@ -1415,16 +1401,12 @@
     "home.tutorials.common.metricbeat.cloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.metricbeat.premCloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.metricbeat.premInstructions.gettingStarted.title": "入门",
-    "home.tutorials.common.metricbeatCloudInstructions.config.debTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.metricbeatCloudInstructions.config.debTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.metricbeatCloudInstructions.config.debTitle": "编辑配置",
-    "home.tutorials.common.metricbeatCloudInstructions.config.osxTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.metricbeatCloudInstructions.config.osxTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.metricbeatCloudInstructions.config.osxTitle": "编辑配置",
-    "home.tutorials.common.metricbeatCloudInstructions.config.rpmTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.metricbeatCloudInstructions.config.rpmTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.metricbeatCloudInstructions.config.rpmTitle": "编辑配置",
-    "home.tutorials.common.metricbeatCloudInstructions.config.windowsTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.metricbeatCloudInstructions.config.windowsTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.metricbeatCloudInstructions.config.windowsTitle": "编辑配置",
     "home.tutorials.common.metricbeatEnableInstructions.debTextPost": "在 `/etc/metricbeat/modules.d/{moduleName}.yml` 文件中修改设置。",
@@ -1479,7 +1461,6 @@
     "home.tutorials.common.winlogbeat.cloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.winlogbeat.premCloudInstructions.gettingStarted.title": "入门",
     "home.tutorials.common.winlogbeat.premInstructions.gettingStarted.title": "入门",
-    "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTextPost": "其中 {passwordTemplate} 是 `elastic` 用户的密码。",
     "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTextPre": "修改 {path} 以设置 Elastic Cloud 的连接信息:",
     "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTitle": "编辑配置",
     "home.tutorials.common.winlogbeatInstructions.config.windowsTextPost": "其中,{passwordTemplate} 是 `elastic` 用户的密码,{esUrlTemplate} 是 Elasticsearch 的 URL,{kibanaUrlTemplate} 是 Kibana 的 URL。",

From 80384c3209d8b49ed43fd2b505cd37f8cbf38ac7 Mon Sep 17 00:00:00 2001
From: Yuliia Naumenko <jo.naumenko@gmail.com>
Date: Thu, 9 Apr 2020 07:50:11 -0700
Subject: [PATCH 21/78] Exposed AddMessageVariables as separate component
 (#63007)

* Exposed AddMessageVariables as separate component and added styles to allow to handle bigger list of messageVariables

* Fixed failing tests and styles

* Fixed due to comments
---
 .../translations/translations/ja-JP.json      |  15 --
 .../translations/translations/zh-CN.json      |  15 --
 .../components/add_message_variables.scss     |   4 +
 .../components/add_message_variables.tsx      |  69 +++++++
 .../components/builtin_action_types/email.tsx |  62 +++---
 .../builtin_action_types/es_index.test.tsx    |   4 +-
 .../builtin_action_types/es_index.tsx         |  62 ++----
 .../builtin_action_types/pagerduty.tsx        | 182 ++++++------------
 .../builtin_action_types/server_log.tsx       |  63 ++----
 .../components/builtin_action_types/slack.tsx |  66 ++-----
 .../builtin_action_types/webhook.test.tsx     |   2 +-
 .../builtin_action_types/webhook.tsx          |  54 +-----
 12 files changed, 211 insertions(+), 387 deletions(-)
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.scss
 create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx

diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 16c4b11bb6a6e..d357e40c02934 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -15846,7 +15846,6 @@
     "xpack.triggersActionsUI.common.expressionItems.threshold.descriptionLabel": "タイミング",
     "xpack.triggersActionsUI.common.expressionItems.threshold.popoverTitle": "タイミング",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.actionTypeTitle": "メールに送信",
-    "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.addVariablePopoverButton": "変数を追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText": "サーバーからメールを送信します。",
     "xpack.triggersActionsUI.components.builtinActionTypes.error.formatFromText": "送信元は有効なメールアドレスではありません。",
     "xpack.triggersActionsUI.components.builtinActionTypes.error.requiredEntryText": "To、Cc、または Bcc のエントリーがありません。 1 つ以上のエントリーが必要です。",
@@ -15875,14 +15874,6 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.indexAction.refreshTooltip": "このチェックボックスは更新インデックス値を設定します。",
     "xpack.triggersActionsUI.components.builtinActionTypes.indexAction.selectMessageText": "データを Elasticsearch にインデックスしてください。",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.actionTypeTitle": "PagerDuty に送信",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton1": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton2": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton3": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton4": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton5": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton6": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton7": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariableTitle": "アラート変数を追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.apiUrlTextFieldLabel": "API URL",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.classFieldLabel": "クラス (任意)",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.componentTextFieldLabel": "コンポーネント(任意)",
@@ -15906,14 +15897,10 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.summaryFieldLabel": "まとめ",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.timestampTextFieldLabel": "タイムスタンプ (任意)",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.actionTypeTitle": "サーバーログに送信",
-    "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.addVariablePopoverButton": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.addVariableTitle": "変数を追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.logLevelFieldLabel": "レベル",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.logMessageFieldLabel": "メッセージ",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.selectMessageText": "Kibana ログにメッセージを追加します。",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.actionTypeTitle": "Slack に送信",
-    "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.addVariablePopoverButton": "アラート変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.addVariableTitle": "アラート変数を追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.error.requiredWebhookUrlText": "Web フック URL が必要です。",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.messageTextAreaFieldLabel": "メッセージ",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.selectMessageText": "Slack チャネルにメッセージを送信します。",
@@ -15922,8 +15909,6 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.actionTypeTitle": "Web フックデータ",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addHeader": "ヘッダーを追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addHeaderButton": "追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addVariablePopoverButton": "変数を追加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addVariableTitle": "変数を追加",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.bodyCodeEditorAriaLabel": "コードエディター",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.bodyFieldLabel": "本文",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.deleteHeaderButton": "削除",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index c81fad386ac2f..839c89f3b1cae 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -15850,7 +15850,6 @@
     "xpack.triggersActionsUI.common.expressionItems.threshold.descriptionLabel": "当",
     "xpack.triggersActionsUI.common.expressionItems.threshold.popoverTitle": "当",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.actionTypeTitle": "发送到电子邮件",
-    "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.addVariablePopoverButton": "添加变量",
     "xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText": "从您的服务器发送电子邮件。",
     "xpack.triggersActionsUI.components.builtinActionTypes.error.formatFromText": "发送者电子邮件地址无效。",
     "xpack.triggersActionsUI.components.builtinActionTypes.error.requiredEntryText": "未输入收件人、抄送、密送。 至少需要输入一个。",
@@ -15879,14 +15878,6 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.indexAction.refreshTooltip": "此复选框设置刷新索引值。",
     "xpack.triggersActionsUI.components.builtinActionTypes.indexAction.selectMessageText": "将数据索引到 Elasticsearch 中。",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.actionTypeTitle": "发送到 PagerDuty",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton1": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton2": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton3": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton4": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton5": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton6": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton7": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariableTitle": "添加告警变量",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.apiUrlTextFieldLabel": "API URL",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.classFieldLabel": "类(可选)",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.componentTextFieldLabel": "组件(可选)",
@@ -15910,14 +15901,10 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.summaryFieldLabel": "摘要",
     "xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.timestampTextFieldLabel": "时间戳(可选)",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.actionTypeTitle": "发送到服务器日志",
-    "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.addVariablePopoverButton": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.addVariableTitle": "添加变量",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.logLevelFieldLabel": "级别",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.logMessageFieldLabel": "消息",
     "xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.selectMessageText": "将消息添加到 Kibana 日志。",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.actionTypeTitle": "发送到 Slack",
-    "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.addVariablePopoverButton": "添加告警变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.addVariableTitle": "添加告警变量",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.error.requiredWebhookUrlText": "Webhook URL 必填。",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.messageTextAreaFieldLabel": "消息",
     "xpack.triggersActionsUI.components.builtinActionTypes.slackAction.selectMessageText": "向 Slack 频道或用户发送消息。",
@@ -15926,8 +15913,6 @@
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.actionTypeTitle": "Webhook 数据",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addHeader": "添加标头",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addHeaderButton": "添加",
-    "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addVariablePopoverButton": "添加变量",
-    "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addVariableTitle": "添加变量",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.bodyCodeEditorAriaLabel": "代码编辑器",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.bodyFieldLabel": "正文",
     "xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.deleteHeaderButton": "删除",
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.scss b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.scss
new file mode 100644
index 0000000000000..996f21c4b6b09
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.scss
@@ -0,0 +1,4 @@
+.messageVariablesPanel {
+  @include euiYScrollWithShadows;
+  max-height: $euiSize * 20;
+}
\ No newline at end of file
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx
new file mode 100644
index 0000000000000..ab9b5c2586c17
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React, { useState } from 'react';
+import { i18n } from '@kbn/i18n';
+import { EuiPopover, EuiButtonIcon, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui';
+import './add_message_variables.scss';
+
+interface Props {
+  messageVariables: string[] | undefined;
+  paramsProperty: string;
+  onSelectEventHandler: (variable: string) => void;
+}
+
+export const AddMessageVariables: React.FunctionComponent<Props> = ({
+  messageVariables,
+  paramsProperty,
+  onSelectEventHandler,
+}) => {
+  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
+
+  const getMessageVariables = () =>
+    messageVariables?.map((variable: string) => (
+      <EuiContextMenuItem
+        key={variable}
+        icon="empty"
+        onClick={() => {
+          onSelectEventHandler(variable);
+          setIsVariablesPopoverOpen(false);
+        }}
+      >
+        {`{{${variable}}}`}
+      </EuiContextMenuItem>
+    ));
+
+  const addVariableButtonTitle = i18n.translate(
+    'xpack.triggersActionsUI.components.addMessageVariables.addVariableTitle',
+    {
+      defaultMessage: 'Add alert variable',
+    }
+  );
+
+  return (
+    <EuiPopover
+      button={
+        <EuiButtonIcon
+          data-test-subj={`${paramsProperty}AddVariableButton`}
+          title={addVariableButtonTitle}
+          onClick={() => setIsVariablesPopoverOpen(true)}
+          iconType="indexOpen"
+          aria-label={i18n.translate(
+            'xpack.triggersActionsUI.components.addMessageVariables.addVariablePopoverButton',
+            {
+              defaultMessage: 'Add variable',
+            }
+          )}
+        />
+      }
+      isOpen={isVariablesPopoverOpen}
+      closePopover={() => setIsVariablesPopoverOpen(false)}
+      panelPaddingSize="none"
+      anchorPosition="downLeft"
+    >
+      <EuiContextMenuPanel className="messageVariablesPanel" items={getMessageVariables()} />
+    </EuiPopover>
+  );
+};
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email.tsx
index b4bbb8af36a19..dff697297f3e4 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email.tsx
@@ -16,10 +16,6 @@ import {
   EuiButtonEmpty,
   EuiSwitch,
   EuiFormRow,
-  EuiContextMenuItem,
-  EuiButtonIcon,
-  EuiContextMenuPanel,
-  EuiPopover,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import {
@@ -29,6 +25,7 @@ import {
   ActionParamsProps,
 } from '../../../types';
 import { EmailActionParams, EmailActionConnector } from './types';
+import { AddMessageVariables } from '../add_message_variables';
 
 export function getActionType(): ActionTypeModel {
   const mailformat = /^[^@\s]+@[^@\s]+$/;
@@ -368,25 +365,21 @@ const EmailParamsFields: React.FunctionComponent<ActionParamsProps<EmailActionPa
   const [addCC, setAddCC] = useState<boolean>(false);
   const [addBCC, setAddBCC] = useState<boolean>(false);
 
-  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
   useEffect(() => {
     if (!message && defaultMessage && defaultMessage.length > 0) {
       editAction('message', defaultMessage, index);
     }
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);
-  const messageVariablesItems = messageVariables?.map((variable: string) => (
-    <EuiContextMenuItem
-      key={variable}
-      icon="empty"
-      onClick={() => {
-        editAction('message', (message ?? '').concat(` {{${variable}}}`), index);
-        setIsVariablesPopoverOpen(false);
-      }}
-    >
-      {`{{${variable}}}`}
-    </EuiContextMenuItem>
-  ));
+
+  const onSelectMessageVariable = (paramsProperty: string, variable: string) => {
+    editAction(
+      paramsProperty,
+      ((actionParams as any)[paramsProperty] ?? '').concat(` {{${variable}}}`),
+      index
+    );
+  };
+
   return (
     <Fragment>
       <EuiFormRow
@@ -543,6 +536,15 @@ const EmailParamsFields: React.FunctionComponent<ActionParamsProps<EmailActionPa
             defaultMessage: 'Subject',
           }
         )}
+        labelAppend={
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) =>
+              onSelectMessageVariable('subject', variable)
+            }
+            paramsProperty="subject"
+          />
+        }
       >
         <EuiFieldText
           fullWidth
@@ -571,27 +573,13 @@ const EmailParamsFields: React.FunctionComponent<ActionParamsProps<EmailActionPa
           }
         )}
         labelAppend={
-          <EuiPopover
-            id="singlePanel"
-            button={
-              <EuiButtonIcon
-                onClick={() => setIsVariablesPopoverOpen(true)}
-                iconType="indexOpen"
-                aria-label={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.addVariablePopoverButton',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-              />
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) =>
+              onSelectMessageVariable('message', variable)
             }
-            isOpen={isVariablesPopoverOpen}
-            closePopover={() => setIsVariablesPopoverOpen(false)}
-            panelPaddingSize="none"
-            anchorPosition="downLeft"
-          >
-            <EuiContextMenuPanel items={messageVariablesItems} />
-          </EuiPopover>
+            paramsProperty="message"
+          />
         }
       >
         <EuiTextArea
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.test.tsx
index d83396f200829..658a0e869548f 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.test.tsx
@@ -152,8 +152,6 @@ describe('IndexParamsFields renders', () => {
     ).toBe(`{
   "test": 123
 }`);
-    expect(
-      wrapper.find('[data-test-subj="indexDocumentAddVariableButton"]').length > 0
-    ).toBeTruthy();
+    expect(wrapper.find('[data-test-subj="documentsAddVariableButton"]').length > 0).toBeTruthy();
   });
 });
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx
index 56d9f40e40021..9bd6a39d216e3 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx
@@ -14,10 +14,6 @@ import {
   EuiSelect,
   EuiTitle,
   EuiIconTip,
-  EuiPopover,
-  EuiButtonIcon,
-  EuiContextMenuPanel,
-  EuiContextMenuItem,
 } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { i18n } from '@kbn/i18n';
@@ -36,6 +32,7 @@ import {
   getIndexPatterns,
 } from '../../../common/index_controls';
 import { useXJsonMode } from '../../lib/use_x_json_mode';
+import { AddMessageVariables } from '../add_message_variables';
 
 export function getActionType(): ActionTypeModel {
   return {
@@ -282,23 +279,13 @@ const IndexParamsFields: React.FunctionComponent<ActionParamsProps<IndexActionPa
   const { xJsonMode, convertToJson, setXJson, xJson } = useXJsonMode(
     documents && documents.length > 0 ? documents[0] : null
   );
-  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
-  const messageVariablesItems = messageVariables?.map((variable: string, i: number) => (
-    <EuiContextMenuItem
-      key={variable}
-      data-test-subj={`variableMenuButton-${i}`}
-      icon="empty"
-      onClick={() => {
-        const value = (xJson ?? '').concat(` {{${variable}}}`);
-        setXJson(value);
-        // Keep the documents in sync with the editor content
-        onDocumentsChange(convertToJson(value));
-        setIsVariablesPopoverOpen(false);
-      }}
-    >
-      {`{{${variable}}}`}
-    </EuiContextMenuItem>
-  ));
+  const onSelectMessageVariable = (variable: string) => {
+    const value = (xJson ?? '').concat(` {{${variable}}}`);
+    setXJson(value);
+    // Keep the documents in sync with the editor content
+    onDocumentsChange(convertToJson(value));
+  };
+
   function onDocumentsChange(updatedDocuments: string) {
     try {
       const documentsJSON = JSON.parse(updatedDocuments);
@@ -317,34 +304,11 @@ const IndexParamsFields: React.FunctionComponent<ActionParamsProps<IndexActionPa
           }
         )}
         labelAppend={
-          // TODO: replace this button with a proper Eui component, when it will be ready
-          <EuiPopover
-            button={
-              <EuiButtonIcon
-                data-test-subj="indexDocumentAddVariableButton"
-                onClick={() => setIsVariablesPopoverOpen(true)}
-                iconType="indexOpen"
-                title={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.addVariableTitle',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-                aria-label={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.addVariablePopoverButton',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-              />
-            }
-            isOpen={isVariablesPopoverOpen}
-            closePopover={() => setIsVariablesPopoverOpen(false)}
-            panelPaddingSize="none"
-            anchorPosition="downLeft"
-          >
-            <EuiContextMenuPanel items={messageVariablesItems} />
-          </EuiPopover>
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) => onSelectMessageVariable(variable)}
+            paramsProperty="documents"
+          />
         }
       >
         <EuiCodeEditor
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty.tsx
index da324050f3242..d99362c618356 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty.tsx
@@ -3,7 +3,7 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React, { Fragment, useState } from 'react';
+import React, { Fragment } from 'react';
 import {
   EuiFieldText,
   EuiFlexGroup,
@@ -11,10 +11,6 @@ import {
   EuiFormRow,
   EuiSelect,
   EuiLink,
-  EuiContextMenuItem,
-  EuiPopover,
-  EuiButtonIcon,
-  EuiContextMenuPanel,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
@@ -26,6 +22,7 @@ import {
 } from '../../../types';
 import { PagerDutyActionParams, PagerDutyActionConnector } from './types';
 import pagerDutySvg from './pagerduty.svg';
+import { AddMessageVariables } from '../add_message_variables';
 
 export function getActionType(): ActionTypeModel {
   return {
@@ -243,66 +240,15 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
       ),
     },
   ];
-  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<Record<string, boolean>>({
-    dedupKey: false,
-    summary: false,
-    source: false,
-    timestamp: false,
-    component: false,
-    group: false,
-    class: false,
-  });
-  // TODO: replace this button with a proper Eui component, when it will be ready
-  const getMessageVariables = (paramsProperty: string) =>
-    messageVariables?.map((variable: string) => (
-      <EuiContextMenuItem
-        key={variable}
-        icon="empty"
-        onClick={() => {
-          editAction(
-            paramsProperty,
-            ((actionParams as any)[paramsProperty] ?? '').concat(` {{${variable}}}`),
-            index
-          );
-          setIsVariablesPopoverOpen({ ...isVariablesPopoverOpen, [paramsProperty]: false });
-        }}
-      >
-        {`{{${variable}}}`}
-      </EuiContextMenuItem>
-    ));
-
-  const addVariableButtonTitle = i18n.translate(
-    'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariableTitle',
-    {
-      defaultMessage: 'Add alert variable',
-    }
-  );
 
-  const getAddVariableComponent = (paramsProperty: string, buttonName: string) => {
-    return (
-      <EuiPopover
-        button={
-          <EuiButtonIcon
-            data-test-subj={`${paramsProperty}AddVariableButton`}
-            title={addVariableButtonTitle}
-            onClick={() =>
-              setIsVariablesPopoverOpen({ ...isVariablesPopoverOpen, [paramsProperty]: true })
-            }
-            iconType="indexOpen"
-            aria-label={buttonName}
-          />
-        }
-        isOpen={isVariablesPopoverOpen[paramsProperty]}
-        closePopover={() =>
-          setIsVariablesPopoverOpen({ ...isVariablesPopoverOpen, [paramsProperty]: false })
-        }
-        panelPaddingSize="none"
-        anchorPosition="downLeft"
-      >
-        <EuiContextMenuPanel items={getMessageVariables(paramsProperty)} />
-      </EuiPopover>
+  const onSelectMessageVariable = (paramsProperty: string, variable: string) => {
+    editAction(
+      paramsProperty,
+      ((actionParams as any)[paramsProperty] ?? '').concat(` {{${variable}}}`),
+      index
     );
   };
+
   return (
     <Fragment>
       <EuiFlexGroup>
@@ -359,15 +305,15 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
                 defaultMessage: 'DedupKey (optional)',
               }
             )}
-            labelAppend={getAddVariableComponent(
-              'dedupKey',
-              i18n.translate(
-                'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton1',
-                {
-                  defaultMessage: 'Add variable',
+            labelAppend={
+              <AddMessageVariables
+                messageVariables={messageVariables}
+                onSelectEventHandler={(variable: string) =>
+                  onSelectMessageVariable('dedupKey', variable)
                 }
-              )
-            )}
+                paramsProperty="dedupKey"
+              />
+            }
           >
             <EuiFieldText
               fullWidth
@@ -394,15 +340,15 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
                 defaultMessage: 'Timestamp (optional)',
               }
             )}
-            labelAppend={getAddVariableComponent(
-              'timestamp',
-              i18n.translate(
-                'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton2',
-                {
-                  defaultMessage: 'Add variable',
+            labelAppend={
+              <AddMessageVariables
+                messageVariables={messageVariables}
+                onSelectEventHandler={(variable: string) =>
+                  onSelectMessageVariable('timestamp', variable)
                 }
-              )
-            )}
+                paramsProperty="timestamp"
+              />
+            }
           >
             <EuiFieldText
               fullWidth
@@ -429,15 +375,15 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
             defaultMessage: 'Component (optional)',
           }
         )}
-        labelAppend={getAddVariableComponent(
-          'component',
-          i18n.translate(
-            'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton3',
-            {
-              defaultMessage: 'Add variable',
+        labelAppend={
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) =>
+              onSelectMessageVariable('component', variable)
             }
-          )
-        )}
+            paramsProperty="component"
+          />
+        }
       >
         <EuiFieldText
           fullWidth
@@ -462,15 +408,13 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
             defaultMessage: 'Group (optional)',
           }
         )}
-        labelAppend={getAddVariableComponent(
-          'group',
-          i18n.translate(
-            'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton4',
-            {
-              defaultMessage: 'Add variable',
-            }
-          )
-        )}
+        labelAppend={
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) => onSelectMessageVariable('group', variable)}
+            paramsProperty="group"
+          />
+        }
       >
         <EuiFieldText
           fullWidth
@@ -495,15 +439,13 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
             defaultMessage: 'Source (optional)',
           }
         )}
-        labelAppend={getAddVariableComponent(
-          'source',
-          i18n.translate(
-            'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton5',
-            {
-              defaultMessage: 'Add variable',
-            }
-          )
-        )}
+        labelAppend={
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) => onSelectMessageVariable('source', variable)}
+            paramsProperty="source"
+          />
+        }
       >
         <EuiFieldText
           fullWidth
@@ -531,15 +473,15 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
             defaultMessage: 'Summary',
           }
         )}
-        labelAppend={getAddVariableComponent(
-          'summary',
-          i18n.translate(
-            'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton6',
-            {
-              defaultMessage: 'Add variable',
+        labelAppend={
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) =>
+              onSelectMessageVariable('summary', variable)
             }
-          )
-        )}
+            paramsProperty="summary"
+          />
+        }
       >
         <EuiFieldText
           fullWidth
@@ -566,15 +508,13 @@ const PagerDutyParamsFields: React.FunctionComponent<ActionParamsProps<PagerDuty
             defaultMessage: 'Class (optional)',
           }
         )}
-        labelAppend={getAddVariableComponent(
-          'class',
-          i18n.translate(
-            'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.addVariablePopoverButton7',
-            {
-              defaultMessage: 'Add variable',
-            }
-          )
-        )}
+        labelAppend={
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) => onSelectMessageVariable('class', variable)}
+            paramsProperty="class"
+          />
+        }
       >
         <EuiFieldText
           fullWidth
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log.tsx
index 8f84e9da5ada0..a4c83ce76f04e 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log.tsx
@@ -3,19 +3,12 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React, { Fragment, useEffect, useState } from 'react';
+import React, { Fragment, useEffect } from 'react';
 import { i18n } from '@kbn/i18n';
-import {
-  EuiSelect,
-  EuiTextArea,
-  EuiFormRow,
-  EuiContextMenuItem,
-  EuiPopover,
-  EuiButtonIcon,
-  EuiContextMenuPanel,
-} from '@elastic/eui';
+import { EuiSelect, EuiTextArea, EuiFormRow } from '@elastic/eui';
 import { ActionTypeModel, ValidationResult, ActionParamsProps } from '../../../types';
 import { ServerLogActionParams } from './types';
+import { AddMessageVariables } from '../add_message_variables';
 
 export function getActionType(): ActionTypeModel {
   return {
@@ -71,7 +64,6 @@ export const ServerLogParamsFields: React.FunctionComponent<ActionParamsProps<
     { value: 'error', text: 'Error' },
     { value: 'fatal', text: 'Fatal' },
   ];
-  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
 
   useEffect(() => {
     editAction('level', 'info', index);
@@ -80,18 +72,11 @@ export const ServerLogParamsFields: React.FunctionComponent<ActionParamsProps<
     }
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);
-  const messageVariablesItems = messageVariables?.map((variable: string) => (
-    <EuiContextMenuItem
-      key={variable}
-      icon="empty"
-      onClick={() => {
-        editAction('message', (message ?? '').concat(` {{${variable}}}`), index);
-        setIsVariablesPopoverOpen(false);
-      }}
-    >
-      {`{{${variable}}}`}
-    </EuiContextMenuItem>
-  ));
+
+  const onSelectMessageVariable = (paramsProperty: string, variable: string) => {
+    editAction(paramsProperty, (message ?? '').concat(` {{${variable}}}`), index);
+  };
+
   return (
     <Fragment>
       <EuiFormRow
@@ -128,33 +113,13 @@ export const ServerLogParamsFields: React.FunctionComponent<ActionParamsProps<
           }
         )}
         labelAppend={
-          <EuiPopover
-            id="singlePanel"
-            button={
-              <EuiButtonIcon
-                onClick={() => setIsVariablesPopoverOpen(true)}
-                iconType="indexOpen"
-                title={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.addVariableTitle',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-                aria-label={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.addVariablePopoverButton',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-              />
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) =>
+              onSelectMessageVariable('message', variable)
             }
-            isOpen={isVariablesPopoverOpen}
-            closePopover={() => setIsVariablesPopoverOpen(false)}
-            panelPaddingSize="none"
-            anchorPosition="downLeft"
-          >
-            <EuiContextMenuPanel items={messageVariablesItems} />
-          </EuiPopover>
+            paramsProperty="message"
+          />
         }
       >
         <EuiTextArea
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack.tsx
index 2ca07e0d57a8e..fd066e172bbfe 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack.tsx
@@ -3,17 +3,8 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React, { Fragment, useState, useEffect } from 'react';
-import {
-  EuiFieldText,
-  EuiTextArea,
-  EuiButtonIcon,
-  EuiFormRow,
-  EuiLink,
-  EuiPopover,
-  EuiContextMenuPanel,
-  EuiContextMenuItem,
-} from '@elastic/eui';
+import React, { Fragment, useEffect } from 'react';
+import { EuiFieldText, EuiTextArea, EuiFormRow, EuiLink } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 import {
@@ -23,6 +14,7 @@ import {
   ActionParamsProps,
 } from '../../../types';
 import { SlackActionParams, SlackActionConnector } from './types';
+import { AddMessageVariables } from '../add_message_variables';
 
 export function getActionType(): ActionTypeModel {
   return {
@@ -141,26 +133,17 @@ const SlackParamsFields: React.FunctionComponent<ActionParamsProps<SlackActionPa
   defaultMessage,
 }) => {
   const { message } = actionParams;
-  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
   useEffect(() => {
     if (!message && defaultMessage && defaultMessage.length > 0) {
       editAction('message', defaultMessage, index);
     }
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);
-  const messageVariablesItems = messageVariables?.map((variable: string, i: number) => (
-    <EuiContextMenuItem
-      key={variable}
-      data-test-subj={`variableMenuButton-${i}`}
-      icon="empty"
-      onClick={() => {
-        editAction('message', (message ?? '').concat(` {{${variable}}}`), index);
-        setIsVariablesPopoverOpen(false);
-      }}
-    >
-      {`{{${variable}}}`}
-    </EuiContextMenuItem>
-  ));
+
+  const onSelectMessageVariable = (paramsProperty: string, variable: string) => {
+    editAction(paramsProperty, (message ?? '').concat(` {{${variable}}}`), index);
+  };
+
   return (
     <Fragment>
       <EuiFormRow
@@ -175,34 +158,13 @@ const SlackParamsFields: React.FunctionComponent<ActionParamsProps<SlackActionPa
           }
         )}
         labelAppend={
-          <EuiPopover
-            id="singlePanel"
-            button={
-              <EuiButtonIcon
-                data-test-subj="slackAddVariableButton"
-                onClick={() => setIsVariablesPopoverOpen(true)}
-                iconType="indexOpen"
-                title={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.addVariableTitle',
-                  {
-                    defaultMessage: 'Add alert variable',
-                  }
-                )}
-                aria-label={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.addVariablePopoverButton',
-                  {
-                    defaultMessage: 'Add alert variable',
-                  }
-                )}
-              />
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) =>
+              onSelectMessageVariable('message', variable)
             }
-            isOpen={isVariablesPopoverOpen}
-            closePopover={() => setIsVariablesPopoverOpen(false)}
-            panelPaddingSize="none"
-            anchorPosition="downLeft"
-          >
-            <EuiContextMenuPanel items={messageVariablesItems} />
-          </EuiPopover>
+            paramsProperty="message"
+          />
         }
       >
         <EuiTextArea
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.test.tsx
index c4489a316d2c0..7d0082708075f 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.test.tsx
@@ -162,7 +162,7 @@ describe('WebhookParamsFields renders', () => {
         .first()
         .prop('value')
     ).toStrictEqual('test message');
-    expect(wrapper.find('[data-test-subj="webhookAddVariableButton"]').length > 0).toBeTruthy();
+    expect(wrapper.find('[data-test-subj="bodyAddVariableButton"]').length > 0).toBeTruthy();
   });
 
   test('params validation fails when body is not valid', () => {
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.tsx
index f611c3715e56a..daa5a6caeabe9 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook.tsx
@@ -22,9 +22,6 @@ import {
   EuiCodeEditor,
   EuiSwitch,
   EuiButtonEmpty,
-  EuiContextMenuItem,
-  EuiPopover,
-  EuiContextMenuPanel,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import {
@@ -34,6 +31,7 @@ import {
   ActionParamsProps,
 } from '../../../types';
 import { WebhookActionParams, WebhookActionConnector } from './types';
+import { AddMessageVariables } from '../add_message_variables';
 
 const HTTP_VERBS = ['post', 'put'];
 
@@ -467,20 +465,9 @@ const WebhookParamsFields: React.FunctionComponent<ActionParamsProps<WebhookActi
   errors,
 }) => {
   const { body } = actionParams;
-  const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
-  const messageVariablesItems = messageVariables?.map((variable: string, i: number) => (
-    <EuiContextMenuItem
-      key={variable}
-      data-test-subj={`variableMenuButton-${i}`}
-      icon="empty"
-      onClick={() => {
-        editAction('body', (body ?? '').concat(` {{${variable}}}`), index);
-        setIsVariablesPopoverOpen(false);
-      }}
-    >
-      {`{{${variable}}}`}
-    </EuiContextMenuItem>
-  ));
+  const onSelectMessageVariable = (paramsProperty: string, variable: string) => {
+    editAction(paramsProperty, (body ?? '').concat(` {{${variable}}}`), index);
+  };
   return (
     <Fragment>
       <EuiFormRow
@@ -495,34 +482,11 @@ const WebhookParamsFields: React.FunctionComponent<ActionParamsProps<WebhookActi
         fullWidth
         error={errors.body}
         labelAppend={
-          // TODO: replace this button with a proper Eui component, when it will be ready
-          <EuiPopover
-            button={
-              <EuiButtonIcon
-                data-test-subj="webhookAddVariableButton"
-                onClick={() => setIsVariablesPopoverOpen(true)}
-                iconType="indexOpen"
-                title={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addVariableTitle',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-                aria-label={i18n.translate(
-                  'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addVariablePopoverButton',
-                  {
-                    defaultMessage: 'Add variable',
-                  }
-                )}
-              />
-            }
-            isOpen={isVariablesPopoverOpen}
-            closePopover={() => setIsVariablesPopoverOpen(false)}
-            panelPaddingSize="none"
-            anchorPosition="downLeft"
-          >
-            <EuiContextMenuPanel items={messageVariablesItems} />
-          </EuiPopover>
+          <AddMessageVariables
+            messageVariables={messageVariables}
+            onSelectEventHandler={(variable: string) => onSelectMessageVariable('body', variable)}
+            paramsProperty="body"
+          />
         }
       >
         <EuiCodeEditor

From 6985478a324832de604a9181f63b0a3ba23666fe Mon Sep 17 00:00:00 2001
From: Brandon Morelli <brandon.morelli@elastic.co>
Date: Thu, 9 Apr 2020 08:22:00 -0700
Subject: [PATCH 22/78] docs: fix rendering of bulleted list (#62855)

---
 docs/user/alerting/index.asciidoc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/user/alerting/index.asciidoc b/docs/user/alerting/index.asciidoc
index b4f7e6af3d61c..c7cf1186a44be 100644
--- a/docs/user/alerting/index.asciidoc
+++ b/docs/user/alerting/index.asciidoc
@@ -163,7 +163,8 @@ If you are using an *on-premises* Elastic Stack deployment with <<using-kibana-w
 [[alerting-security]]
 == Security
 
-To access alerting in a space, a user must have access to one of the following features: 
+To access alerting in a space, a user must have access to one of the following features:
+
 * <<xpack-apm,*APM*>>
 * <<xpack-infra,*Metrics*>>
 * <<xpack-siem,*SIEM*>>

From a0c247b9cc165638c3c01c87ce02c13ac2a4a698 Mon Sep 17 00:00:00 2001
From: Sandra Gonzales <neptunian@users.noreply.github.com>
Date: Thu, 9 Apr 2020 11:42:10 -0400
Subject: [PATCH 23/78] [EPM] Change PACKAGES_SAVED_OBJECT_TYPE id (#62818)

* changed PACKAGES_SAVED_OBJECT_TYPE id from packageName-version to packageName

* change references to keys to package and version

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../server/routes/epm/handlers.ts             |  4 +-
 .../server/services/datasource.ts             | 10 ++--
 .../services/epm/elasticsearch/ilm/install.ts | 12 +++--
 .../elasticsearch/ingest_pipeline/install.ts  | 23 +++++----
 .../epm/elasticsearch/template/install.ts     | 17 +++++--
 .../epm/kibana/index_pattern/install.ts       | 27 +++++++----
 .../server/services/epm/packages/assets.ts    |  2 +-
 .../server/services/epm/packages/get.ts       | 40 +++++-----------
 .../services/epm/packages/get_objects.ts      | 40 ----------------
 .../server/services/epm/packages/index.ts     |  1 -
 .../server/services/epm/packages/install.ts   | 47 ++++++++++++-------
 .../server/services/epm/packages/remove.ts    |  6 ++-
 .../server/services/epm/registry/index.ts     | 25 +++++-----
 .../ingest_manager/server/services/setup.ts   |  3 +-
 14 files changed, 118 insertions(+), 139 deletions(-)

diff --git a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts
index 48f37a4d65ac6..ad16e1dde456b 100644
--- a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts
+++ b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts
@@ -102,7 +102,9 @@ export const getInfoHandler: RequestHandler<TypeOf<typeof GetInfoRequestSchema.p
   try {
     const { pkgkey } = request.params;
     const savedObjectsClient = context.core.savedObjects.client;
-    const res = await getPackageInfo({ savedObjectsClient, pkgkey });
+    // TODO: change epm API to /packageName/version so we don't need to do this
+    const [pkgName, pkgVersion] = pkgkey.split('-');
+    const res = await getPackageInfo({ savedObjectsClient, pkgName, pkgVersion });
     const body: GetInfoResponse = {
       response: res,
       success: true,
diff --git a/x-pack/plugins/ingest_manager/server/services/datasource.ts b/x-pack/plugins/ingest_manager/server/services/datasource.ts
index 8fa1428f3a055..1b8f2a690b94d 100644
--- a/x-pack/plugins/ingest_manager/server/services/datasource.ts
+++ b/x-pack/plugins/ingest_manager/server/services/datasource.ts
@@ -9,7 +9,7 @@ import { DeleteDatasourcesResponse, packageToConfigDatasource } from '../../comm
 import { DATASOURCE_SAVED_OBJECT_TYPE } from '../constants';
 import { NewDatasource, Datasource, ListWithKuery } from '../types';
 import { agentConfigService } from './agent_config';
-import { findInstalledPackageByName, getPackageInfo } from './epm/packages';
+import { getPackageInfo, getInstallation } from './epm/packages';
 import { outputService } from './output';
 
 const SAVED_OBJECT_TYPE = DATASOURCE_SAVED_OBJECT_TYPE;
@@ -172,15 +172,13 @@ class DatasourceService {
     soClient: SavedObjectsClientContract,
     pkgName: string
   ): Promise<NewDatasource | undefined> {
-    const pkgInstall = await findInstalledPackageByName({
-      savedObjectsClient: soClient,
-      pkgName,
-    });
+    const pkgInstall = await getInstallation({ savedObjectsClient: soClient, pkgName });
     if (pkgInstall) {
       const [pkgInfo, defaultOutputId] = await Promise.all([
         getPackageInfo({
           savedObjectsClient: soClient,
-          pkgkey: `${pkgInstall.name}-${pkgInstall.version}`,
+          pkgName: pkgInstall.name,
+          pkgVersion: pkgInstall.version,
         }),
         outputService.getDefaultOutputId(soClient),
       ]);
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ilm/install.ts
index c56322239f27b..60a85e367079f 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ilm/install.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ilm/install.ts
@@ -7,9 +7,15 @@
 import { CallESAsCurrentUser, ElasticsearchAssetType } from '../../../../types';
 import * as Registry from '../../registry';
 
-export async function installILMPolicy(pkgkey: string, callCluster: CallESAsCurrentUser) {
-  const ilmPaths = await Registry.getArchiveInfo(pkgkey, (entry: Registry.ArchiveEntry) =>
-    isILMPolicy(entry)
+export async function installILMPolicy(
+  pkgName: string,
+  pkgVersion: string,
+  callCluster: CallESAsCurrentUser
+) {
+  const ilmPaths = await Registry.getArchiveInfo(
+    pkgName,
+    pkgVersion,
+    (entry: Registry.ArchiveEntry) => isILMPolicy(entry)
   );
   if (!ilmPaths.length) return;
   await Promise.all(
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts
index 4b65e5554567e..2bbb555ef7393 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts
@@ -30,11 +30,10 @@ export const installPipelines = async (
       if (dataset.ingest_pipeline) {
         acc.push(
           installPipelinesForDataset({
-            pkgkey: Registry.pkgToPkgKey(registryPackage),
             dataset,
             callCluster,
-            packageName: registryPackage.name,
-            packageVersion: registryPackage.version,
+            pkgName: registryPackage.name,
+            pkgVersion: registryPackage.version,
           })
         );
       }
@@ -68,19 +67,19 @@ export function rewriteIngestPipeline(
 
 export async function installPipelinesForDataset({
   callCluster,
-  pkgkey,
+  pkgName,
+  pkgVersion,
   dataset,
-  packageName,
-  packageVersion,
 }: {
   callCluster: CallESAsCurrentUser;
-  pkgkey: string;
+  pkgName: string;
+  pkgVersion: string;
   dataset: Dataset;
-  packageName: string;
-  packageVersion: string;
 }): Promise<AssetReference[]> {
-  const pipelinePaths = await Registry.getArchiveInfo(pkgkey, (entry: Registry.ArchiveEntry) =>
-    isDatasetPipeline(entry, dataset.path)
+  const pipelinePaths = await Registry.getArchiveInfo(
+    pkgName,
+    pkgVersion,
+    (entry: Registry.ArchiveEntry) => isDatasetPipeline(entry, dataset.path)
   );
   let pipelines: any[] = [];
   const substitutions: RewriteSubstitution[] = [];
@@ -90,7 +89,7 @@ export async function installPipelinesForDataset({
     const nameForInstallation = getPipelineNameForInstallation({
       pipelineName: name,
       dataset,
-      packageVersion,
+      packageVersion: pkgVersion,
     });
     const content = Registry.getAsset(path).toString('utf-8');
     pipelines.push({
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts
index de4ba25590c98..560ddfc1f6885 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts
@@ -20,11 +20,12 @@ import * as Registry from '../../registry';
 export const installTemplates = async (
   registryPackage: RegistryPackage,
   callCluster: CallESAsCurrentUser,
-  pkgkey: string
+  pkgName: string,
+  pkgVersion: string
 ) => {
   // install any pre-built index template assets,
   // atm, this is only the base package's global template
-  installPreBuiltTemplates(pkgkey, callCluster);
+  installPreBuiltTemplates(pkgName, pkgVersion, callCluster);
 
   // build templates per dataset from yml files
   const datasets = registryPackage.datasets;
@@ -45,9 +46,15 @@ export const installTemplates = async (
 };
 
 // this is temporary until we update the registry to use index templates v2 structure
-const installPreBuiltTemplates = async (pkgkey: string, callCluster: CallESAsCurrentUser) => {
-  const templatePaths = await Registry.getArchiveInfo(pkgkey, (entry: Registry.ArchiveEntry) =>
-    isTemplate(entry)
+const installPreBuiltTemplates = async (
+  pkgName: string,
+  pkgVersion: string,
+  callCluster: CallESAsCurrentUser
+) => {
+  const templatePaths = await Registry.getArchiveInfo(
+    pkgName,
+    pkgVersion,
+    (entry: Registry.ArchiveEntry) => isTemplate(entry)
   );
   templatePaths.forEach(async path => {
     const { file } = Registry.pathParts(path);
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts
index 0657fb7759b49..05e64c6565dc6 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts
@@ -68,25 +68,32 @@ export enum IndexPatternType {
   metrics = 'metrics',
   events = 'events',
 }
-
+// TODO: use a function overload and make pkgName and pkgVersion required for install/update
+// and not for an update removal.  or separate out the functions
 export async function installIndexPatterns(
   savedObjectsClient: SavedObjectsClientContract,
-  pkgkey?: string
+  pkgName?: string,
+  pkgVersion?: string
 ) {
   // get all user installed packages
   const installedPackages = await getPackageKeysByStatus(
     savedObjectsClient,
     InstallationStatus.installed
   );
-  // add this package to the array if it doesn't already exist
-  // this should not happen because a user can't "reinstall" a package
-  // if it does because the install endpoint is called directly, the install continues
-  if (pkgkey && !installedPackages.includes(pkgkey)) {
-    installedPackages.push(pkgkey);
+  if (pkgName && pkgVersion) {
+    // add this package to the array if it doesn't already exist
+    const foundPkg = installedPackages.find(pkg => pkg.pkgName === pkgName);
+    // this may be removed if we add the packged to saved objects before installing index patterns
+    // otherwise this is a first time install
+    // TODO: handle update case when versions are different
+    if (!foundPkg) {
+      installedPackages.push({ pkgName, pkgVersion });
+    }
   }
-
   // get each package's registry info
-  const installedPackagesFetchInfoPromise = installedPackages.map(pkg => Registry.fetchInfo(pkg));
+  const installedPackagesFetchInfoPromise = installedPackages.map(pkg =>
+    Registry.fetchInfo(pkg.pkgName, pkg.pkgVersion)
+  );
   const installedPackagesInfo = await Promise.all(installedPackagesFetchInfoPromise);
 
   // for each index pattern type, create an index pattern
@@ -97,7 +104,7 @@ export async function installIndexPatterns(
   ];
   indexPatternTypes.forEach(async indexPatternType => {
     // if this is an update because a package is being unisntalled (no pkgkey argument passed) and no other packages are installed, remove the index pattern
-    if (!pkgkey && installedPackages.length === 0) {
+    if (!pkgName && installedPackages.length === 0) {
       try {
         await savedObjectsClient.delete(INDEX_PATTERN_SAVED_OBJECT_TYPE, `${indexPatternType}-*`);
       } catch (err) {
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts
index d7a5c5569986e..7026d9eae24c3 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts
@@ -58,7 +58,7 @@ export async function getAssetsData(
 ): Promise<Registry.ArchiveEntry[]> {
   // TODO: Needs to be called to fill the cache but should not be required
   const pkgkey = packageInfo.name + '-' + packageInfo.version;
-  if (!cacheHas(pkgkey)) await Registry.getArchiveInfo(pkgkey);
+  if (!cacheHas(pkgkey)) await Registry.getArchiveInfo(packageInfo.name, packageInfo.version);
 
   // Gather all asset data
   const assets = getAssets(packageInfo, filter, datasetName);
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts
index e963ea138dfd5..0e2c2a3d26073 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts
@@ -41,7 +41,7 @@ export async function getPackages(
     .map(item =>
       createInstallableFrom(
         item,
-        savedObjectsVisible.find(({ attributes }) => attributes.name === item.name)
+        savedObjectsVisible.find(({ id }) => id === item.name)
       )
     )
     .sort(sortByName);
@@ -53,9 +53,9 @@ export async function getPackageKeysByStatus(
   status: InstallationStatus
 ) {
   const allPackages = await getPackages({ savedObjectsClient });
-  return allPackages.reduce<string[]>((acc, pkg) => {
+  return allPackages.reduce<Array<{ pkgName: string; pkgVersion: string }>>((acc, pkg) => {
     if (pkg.status === status) {
-      acc.push(`${pkg.name}-${pkg.version}`);
+      acc.push({ pkgName: pkg.name, pkgVersion: pkg.version });
     }
     return acc;
   }, []);
@@ -63,13 +63,14 @@ export async function getPackageKeysByStatus(
 
 export async function getPackageInfo(options: {
   savedObjectsClient: SavedObjectsClientContract;
-  pkgkey: string;
+  pkgName: string;
+  pkgVersion: string;
 }): Promise<PackageInfo> {
-  const { savedObjectsClient, pkgkey } = options;
+  const { savedObjectsClient, pkgName, pkgVersion } = options;
   const [item, savedObject] = await Promise.all([
-    Registry.fetchInfo(pkgkey),
-    getInstallationObject({ savedObjectsClient, pkgkey }),
-    Registry.getArchiveInfo(pkgkey),
+    Registry.fetchInfo(pkgName, pkgVersion),
+    getInstallationObject({ savedObjectsClient, pkgName }),
+    Registry.getArchiveInfo(pkgName, pkgVersion),
   ] as const);
   // adding `as const` due to regression in TS 3.7.2
   // see https://github.com/microsoft/TypeScript/issues/34925#issuecomment-550021453
@@ -86,37 +87,22 @@ export async function getPackageInfo(options: {
 
 export async function getInstallationObject(options: {
   savedObjectsClient: SavedObjectsClientContract;
-  pkgkey: string;
+  pkgName: string;
 }) {
-  const { savedObjectsClient, pkgkey } = options;
+  const { savedObjectsClient, pkgName } = options;
   return savedObjectsClient
-    .get<Installation>(PACKAGES_SAVED_OBJECT_TYPE, pkgkey)
+    .get<Installation>(PACKAGES_SAVED_OBJECT_TYPE, pkgName)
     .catch(e => undefined);
 }
 
 export async function getInstallation(options: {
   savedObjectsClient: SavedObjectsClientContract;
-  pkgkey: string;
+  pkgName: string;
 }) {
   const savedObject = await getInstallationObject(options);
   return savedObject?.attributes;
 }
 
-export async function findInstalledPackageByName(options: {
-  savedObjectsClient: SavedObjectsClientContract;
-  pkgName: string;
-}): Promise<Installation | undefined> {
-  const { savedObjectsClient, pkgName } = options;
-
-  const res = await savedObjectsClient.find<Installation>({
-    type: PACKAGES_SAVED_OBJECT_TYPE,
-    search: pkgName,
-    searchFields: ['name'],
-  });
-  if (res.saved_objects.length) return res.saved_objects[0].attributes;
-  return undefined;
-}
-
 function sortByName(a: { name: string }, b: { name: string }) {
   if (a.name > b.name) {
     return 1;
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/get_objects.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/get_objects.ts
index b924c045870f3..b623295c5e060 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/get_objects.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/get_objects.ts
@@ -11,46 +11,6 @@ import * as Registry from '../registry';
 type ArchiveAsset = Pick<SavedObject, 'attributes' | 'migrationVersion' | 'references'>;
 type SavedObjectToBe = Required<SavedObjectsBulkCreateObject> & { type: AssetType };
 
-export async function getObjects(
-  pkgkey: string,
-  filter = (entry: Registry.ArchiveEntry): boolean => true
-): Promise<SavedObjectToBe[]> {
-  // Create a Map b/c some values, especially index-patterns, are referenced multiple times
-  const objects: Map<string, SavedObjectToBe> = new Map();
-
-  // Get paths which match the given filter
-  const paths = await Registry.getArchiveInfo(pkgkey, filter);
-
-  // Get all objects which matched filter. Add them to the Map
-  const rootObjects = await Promise.all(paths.map(getObject));
-  rootObjects.forEach(obj => objects.set(obj.id, obj));
-
-  // Each of those objects might have `references` property like [{id, type, name}]
-  for (const object of rootObjects) {
-    // For each of those objects, if they have references
-    for (const reference of object.references) {
-      // Get the referenced objects. Call same function with a new filter
-      const referencedObjects = await getObjects(pkgkey, (entry: Registry.ArchiveEntry) => {
-        // Skip anything we've already stored
-        if (objects.has(reference.id)) return false;
-
-        // Is the archive entry the reference we want?
-        const { type, file } = Registry.pathParts(entry.path);
-        const isType = type === reference.type;
-        const isJson = file === `${reference.id}.json`;
-
-        return isType && isJson;
-      });
-
-      // Add referenced objects to the Map
-      referencedObjects.forEach(ro => objects.set(ro.id, ro));
-    }
-  }
-
-  // return the array of unique objects
-  return Array.from(objects.values());
-}
-
 export async function getObject(key: string) {
   const buffer = Registry.getAsset(key);
 
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts
index 79259ce79ff41..d49e0e661440f 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts
@@ -21,7 +21,6 @@ export {
   getPackageInfo,
   getPackages,
   SearchParams,
-  findInstalledPackageByName,
 } from './get';
 
 export { installKibanaAssets, installPackage, ensureInstalledPackage } from './install';
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts
index 82523e37509d1..e250b4f176819 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts
@@ -16,7 +16,7 @@ import {
 import { installIndexPatterns } from '../kibana/index_pattern/install';
 import * as Registry from '../registry';
 import { getObject } from './get_objects';
-import { getInstallation, findInstalledPackageByName } from './index';
+import { getInstallation } from './index';
 import { installTemplates } from '../elasticsearch/template/install';
 import { installPipelines } from '../elasticsearch/ingest_pipeline/install';
 import { installILMPolicy } from '../elasticsearch/ilm/install';
@@ -63,7 +63,7 @@ export async function ensureInstalledPackage(options: {
   callCluster: CallESAsCurrentUser;
 }): Promise<Installation | undefined> {
   const { savedObjectsClient, pkgName, callCluster } = options;
-  const installedPackage = await findInstalledPackageByName({ savedObjectsClient, pkgName });
+  const installedPackage = await getInstallation({ savedObjectsClient, pkgName });
   if (installedPackage) {
     return installedPackage;
   }
@@ -74,7 +74,7 @@ export async function ensureInstalledPackage(options: {
       pkgName,
       callCluster,
     });
-    return await findInstalledPackageByName({ savedObjectsClient, pkgName });
+    return await getInstallation({ savedObjectsClient, pkgName });
   } catch (err) {
     throw new Error(err.message);
   }
@@ -86,22 +86,30 @@ export async function installPackage(options: {
   callCluster: CallESAsCurrentUser;
 }): Promise<AssetReference[]> {
   const { savedObjectsClient, pkgkey, callCluster } = options;
-  const registryPackageInfo = await Registry.fetchInfo(pkgkey);
-  const { name: pkgName, version: pkgVersion, internal = false } = registryPackageInfo;
+  // TODO: change epm API to /packageName/version so we don't need to do this
+  const [pkgName, pkgVersion] = pkgkey.split('-');
+  const registryPackageInfo = await Registry.fetchInfo(pkgName, pkgVersion);
+  const { internal = false } = registryPackageInfo;
 
   const installKibanaAssetsPromise = installKibanaAssets({
     savedObjectsClient,
-    pkgkey,
+    pkgName,
+    pkgVersion,
   });
   const installPipelinePromises = installPipelines(registryPackageInfo, callCluster);
-  const installTemplatePromises = installTemplates(registryPackageInfo, callCluster, pkgkey);
+  const installTemplatePromises = installTemplates(
+    registryPackageInfo,
+    callCluster,
+    pkgName,
+    pkgVersion
+  );
 
   // index patterns and ilm policies are not currently associated with a particular package
   // so we do not save them in the package saved object state.  at some point ILM policies can be installed/modified
   // per dataset and we should then save them
-  await installIndexPatterns(savedObjectsClient, pkgkey);
+  await installIndexPatterns(savedObjectsClient, pkgName, pkgVersion);
   // currenly only the base package has an ILM policy
-  await installILMPolicy(pkgkey, callCluster);
+  await installILMPolicy(pkgName, pkgVersion, callCluster);
 
   const res = await Promise.all([
     installKibanaAssetsPromise,
@@ -126,14 +134,15 @@ export async function installPackage(options: {
 // e.g. switch statement with cases for each enum key returning `never` for default case
 export async function installKibanaAssets(options: {
   savedObjectsClient: SavedObjectsClientContract;
-  pkgkey: string;
+  pkgName: string;
+  pkgVersion: string;
 }) {
-  const { savedObjectsClient, pkgkey } = options;
+  const { savedObjectsClient, pkgName, pkgVersion } = options;
 
   // Only install Kibana assets during package installation.
   const kibanaAssetTypes = Object.values(KibanaAssetType);
   const installationPromises = kibanaAssetTypes.map(async assetType =>
-    installKibanaSavedObjects({ savedObjectsClient, pkgkey, assetType })
+    installKibanaSavedObjects({ savedObjectsClient, pkgName, pkgVersion, assetType })
   );
 
   // installKibanaSavedObjects returns AssetReference[], so .map creates AssetReference[][]
@@ -149,8 +158,8 @@ export async function saveInstallationReferences(options: {
   internal: boolean;
   toSave: AssetReference[];
 }) {
-  const { savedObjectsClient, pkgkey, pkgName, pkgVersion, internal, toSave } = options;
-  const installation = await getInstallation({ savedObjectsClient, pkgkey });
+  const { savedObjectsClient, pkgName, pkgVersion, internal, toSave } = options;
+  const installation = await getInstallation({ savedObjectsClient, pkgName });
   const savedRefs = installation?.installed || [];
   const mergeRefsReducer = (current: AssetReference[], pending: AssetReference) => {
     const hasRef = current.find(c => c.id === pending.id && c.type === pending.type);
@@ -162,7 +171,7 @@ export async function saveInstallationReferences(options: {
   await savedObjectsClient.create<Installation>(
     PACKAGES_SAVED_OBJECT_TYPE,
     { installed: toInstall, name: pkgName, version: pkgVersion, internal },
-    { id: pkgkey, overwrite: true }
+    { id: pkgName, overwrite: true }
   );
 
   return toInstall;
@@ -170,16 +179,18 @@ export async function saveInstallationReferences(options: {
 
 async function installKibanaSavedObjects({
   savedObjectsClient,
-  pkgkey,
+  pkgName,
+  pkgVersion,
   assetType,
 }: {
   savedObjectsClient: SavedObjectsClientContract;
-  pkgkey: string;
+  pkgName: string;
+  pkgVersion: string;
   assetType: KibanaAssetType;
 }) {
   const isSameType = ({ path }: Registry.ArchiveEntry) =>
     assetType === Registry.pathParts(path).type;
-  const paths = await Registry.getArchiveInfo(pkgkey, isSameType);
+  const paths = await Registry.getArchiveInfo(pkgName, pkgVersion, isSameType);
   const toBeSavedObjects = await Promise.all(paths.map(getObject));
 
   if (toBeSavedObjects.length === 0) {
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts
index 2e73160453c2b..a30acb97b99cf 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts
@@ -17,12 +17,14 @@ export async function removeInstallation(options: {
   callCluster: CallESAsCurrentUser;
 }): Promise<AssetReference[]> {
   const { savedObjectsClient, pkgkey, callCluster } = options;
-  const installation = await getInstallation({ savedObjectsClient, pkgkey });
+  // TODO:  the epm api should change to /name/version so we don't need to do this
+  const [pkgName] = pkgkey.split('-');
+  const installation = await getInstallation({ savedObjectsClient, pkgName });
   const installedObjects = installation?.installed || [];
 
   // Delete the manager saved object with references to the asset objects
   // could also update with [] or some other state
-  await savedObjectsClient.delete(PACKAGES_SAVED_OBJECT_TYPE, pkgkey);
+  await savedObjectsClient.delete(PACKAGES_SAVED_OBJECT_TYPE, pkgName);
 
   // recreate or delete index patterns when a package is uninstalled
   await installIndexPatterns(savedObjectsClient);
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts b/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts
index 36a04b88bba29..a96afc5eb7fa5 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts
@@ -56,10 +56,9 @@ export async function fetchFindLatestPackage(
   }
 }
 
-export async function fetchInfo(pkgkey: string): Promise<RegistryPackage> {
+export async function fetchInfo(pkgName: string, pkgVersion: string): Promise<RegistryPackage> {
   const registryUrl = appContextService.getConfig()?.epm.registryUrl;
-  // change pkg-version to pkg/version
-  return fetchUrl(`${registryUrl}/package/${pkgkey.replace('-', '/')}`).then(JSON.parse);
+  return fetchUrl(`${registryUrl}/package/${pkgName}/${pkgVersion}`).then(JSON.parse);
 }
 
 export async function fetchFile(filePath: string): Promise<Response> {
@@ -73,7 +72,8 @@ export async function fetchCategories(): Promise<CategorySummaryList> {
 }
 
 export async function getArchiveInfo(
-  pkgkey: string,
+  pkgName: string,
+  pkgVersion: string,
   filter = (entry: ArchiveEntry): boolean => true
 ): Promise<string[]> {
   const paths: string[] = [];
@@ -87,7 +87,7 @@ export async function getArchiveInfo(
     }
   };
 
-  await extract(pkgkey, filter, onEntry);
+  await extract(pkgName, pkgVersion, filter, onEntry);
 
   return paths;
 }
@@ -123,21 +123,22 @@ export function pathParts(path: string): AssetParts {
 }
 
 async function extract(
-  pkgkey: string,
+  pkgName: string,
+  pkgVersion: string,
   filter = (entry: ArchiveEntry): boolean => true,
   onEntry: (entry: ArchiveEntry) => void
 ) {
-  const archiveBuffer = await getOrFetchArchiveBuffer(pkgkey);
+  const archiveBuffer = await getOrFetchArchiveBuffer(pkgName, pkgVersion);
 
   return untarBuffer(archiveBuffer, filter, onEntry);
 }
 
-async function getOrFetchArchiveBuffer(pkgkey: string): Promise<Buffer> {
+async function getOrFetchArchiveBuffer(pkgName: string, pkgVersion: string): Promise<Buffer> {
   // assume .tar.gz for now. add support for .zip if/when we need it
-  const key = `${pkgkey}.tar.gz`;
+  const key = `${pkgName}-${pkgVersion}.tar.gz`;
   let buffer = cacheGet(key);
   if (!buffer) {
-    buffer = await fetchArchiveBuffer(pkgkey);
+    buffer = await fetchArchiveBuffer(pkgName, pkgVersion);
     cacheSet(key, buffer);
   }
 
@@ -148,8 +149,8 @@ async function getOrFetchArchiveBuffer(pkgkey: string): Promise<Buffer> {
   }
 }
 
-async function fetchArchiveBuffer(key: string): Promise<Buffer> {
-  const { download: archivePath } = await fetchInfo(key);
+async function fetchArchiveBuffer(pkgName: string, pkgVersion: string): Promise<Buffer> {
+  const { download: archivePath } = await fetchInfo(pkgName, pkgVersion);
   const registryUrl = appContextService.getConfig()?.epm.registryUrl;
   return getResponseStream(`${registryUrl}${archivePath}`).then(streamToBuffer);
 }
diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts
index 224355ced7cb1..bbaf083fb8396 100644
--- a/x-pack/plugins/ingest_manager/server/services/setup.ts
+++ b/x-pack/plugins/ingest_manager/server/services/setup.ts
@@ -120,7 +120,8 @@ async function addPackageToConfig(
 ) {
   const packageInfo = await getPackageInfo({
     savedObjectsClient: soClient,
-    pkgkey: `${packageToInstall.name}-${packageToInstall.version}`,
+    pkgName: packageToInstall.name,
+    pkgVersion: packageToInstall.version,
   });
   await datasourceService.create(
     soClient,

From fddf6cbee5ca1e486f6bc2724d55b2143e93fe74 Mon Sep 17 00:00:00 2001
From: Brandon Morelli <brandon.morelli@elastic.co>
Date: Thu, 9 Apr 2020 08:52:06 -0700
Subject: [PATCH 24/78] [APM] docs: add alerting examples for APM (#62864)

---
 docs/apm/apm-alerts.asciidoc       |  97 +++++++++++++++++++++++++++++
 docs/apm/images/apm-alert.png      | Bin 0 -> 658181 bytes
 docs/apm/using-the-apm-ui.asciidoc |   3 +
 3 files changed, 100 insertions(+)
 create mode 100644 docs/apm/apm-alerts.asciidoc
 create mode 100644 docs/apm/images/apm-alert.png

diff --git a/docs/apm/apm-alerts.asciidoc b/docs/apm/apm-alerts.asciidoc
new file mode 100644
index 0000000000000..b8552c007b13d
--- /dev/null
+++ b/docs/apm/apm-alerts.asciidoc
@@ -0,0 +1,97 @@
+[role="xpack"]
+[[apm-alerts]]
+=== Create an alert
+
+beta::[]
+
+The APM app is integrated with Kibana's {kibana-ref}/alerting-getting-started.html[alerting and actions] feature.
+It provides a set of built-in **actions** and APM specific threshold **alerts** for you to use,
+and allows all alerts to be centrally managed from <<management,Kibana Management>>.
+
+[role="screenshot"]
+image::apm/images/apm-alert.png[Create an alert in the APM app]
+
+There are two different types of threshold alerts: transaction duration, and error rate.
+Below, we'll create one of each.
+
+[float]
+[[apm-create-transaction-alert]]
+=== Create a transaction duration alert
+
+This guide creates an alert for the `opbeans-java` service based on the following criteria:
+
+* Transaction type: `transaction.type:request`
+* Average request is above `1500ms` for the last 5 minutes
+* Check every 10 minutes, and repeat the alert every 30 minutes
+* Send the alert via Slack
+
+From the APM app, navigate to the `opbeans-java` service and select
+**Alerts** > **Create threshold alert** > **Transaction duration**.
+
+The name of your alert will automatically be set as `Transaction duration | opbeans-java`,
+and the alert will be tagged with `apm` and `service.name:opbeans-java`.
+Feel free to edit either of these defaults.
+
+Based on the alert criteria, define the following alert details:
+
+* **Check every** - `10 minutes`
+* **Notify every** - `30 minutes`
+* **TYPE** - `request`
+* **WHEN** - `avg`
+* **IS ABOVE** - `1500ms`
+* **FOR THE LAST** - `5 minutes`
+
+Select an action type.
+Multiple action types can be selected, but in this example we want to post to a slack channel.
+Select **Slack** > **Create a connector**.
+Enter a name for the connector,
+and paste the webhook URL.
+See Slack's webhook documentation if you need to create one.
+
+Select **Save**. The alert has been created and is now active!
+
+[float]
+[[apm-create-error-alert]]
+=== Create an error rate alert
+
+This guide creates an alert for the `opbeans-python` service based on the following criteria:
+
+* Error rate is above 25 for the last minute
+* Check every 1 minute, and repeat the alert every 10 minutes
+* Send the alert via email to the `opbeans-python` team
+
+From the APM app, navigate to the `opbeans-python` service and select
+**Alerts** > **Create threshold alert** > **Error rate**.
+
+The name of your alert will automatically be set as `Error rate | opbeans-python`,
+and the alert will be tagged with `apm` and `service.name:opbeans-python`.
+Feel free to edit either of these defaults.
+
+Based on the alert criteria, define the following alert details:
+
+* **Check every** - `1 minute`
+* **Notify every** - `10 minutes`
+* **IS ABOVE** - `25 errors`
+* **FOR THE LAST** - `1 minute`
+
+Select the **Email** action type and click **Create a connector**.
+Fill out the required details: sender, host, port, etc., and click **save**.
+
+Select **Save**. The alert has been created and is now active!
+
+[float]
+[[apm-alert-manage]]
+=== Manage alerts and actions
+
+From the APM app, select **Alerts** > **View active alerts** to be taken to the Kibana alerts and actions management page.
+From this page, you can create, edit, disable, mute, and delete alerts, and create, edit, and disable connectors.
+
+[float]
+[[apm-alert-more-info]]
+=== More information
+
+See {kibana-ref}/alerting-getting-started.html[alerting and actions] for more information.
+
+NOTE: If you are using an **on-premise** Elastic Stack deployment with security,
+TLS must be configured for communication between Elasticsearch and Kibana.
+More information is in the alerting {kibana-ref}/alerting-getting-started.html#alerting-setup-prerequisites[prerequisites].
\ No newline at end of file
diff --git a/docs/apm/images/apm-alert.png b/docs/apm/images/apm-alert.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cee7214637f8e235db2f9ee1201c603cfdb8aa7
GIT binary patch
literal 658181
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%0D@aYx
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
Q1@I#&CMQ}btn2gt0O?oeDF6Tf

literal 0
HcmV?d00001

diff --git a/docs/apm/using-the-apm-ui.asciidoc b/docs/apm/using-the-apm-ui.asciidoc
index b1b7ed7307986..904718999069d 100644
--- a/docs/apm/using-the-apm-ui.asciidoc
+++ b/docs/apm/using-the-apm-ui.asciidoc
@@ -15,6 +15,7 @@ APM is available via the navigation sidebar in {Kib}.
 * <<spans>>
 * <<errors>>
 * <<metrics>>
+* <<apm-alerts>>
 * <<machine-learning-integration>>
 * <<agent-configuration>>
 * <<advanced-queries>>
@@ -37,6 +38,8 @@ include::errors.asciidoc[]
 
 include::metrics.asciidoc[]
 
+include::apm-alerts.asciidoc[]
+
 include::agent-configuration.asciidoc[]
 
 include::custom-links.asciidoc[]

From 13fe738b2a59c5117e15aca4af1c155e00129a37 Mon Sep 17 00:00:00 2001
From: gchaps <33642766+gchaps@users.noreply.github.com>
Date: Thu, 9 Apr 2020 08:55:29 -0700
Subject: [PATCH 25/78] [UI COPY] Fixes typo in max_shingle_size for
 search_as_you_type (#63071)

---
 .../field_parameters/max_shingle_size_parameter.tsx             | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx
index bc1917b2da966..cec97fb925eef 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx
@@ -23,7 +23,7 @@ export const MaxShingleSizeParameter = ({ defaultToggleValue }: Props) => (
     })}
     description={i18n.translate('xpack.idxMgmt.mappingsEditor.maxShingleSizeFieldDescription', {
       defaultMessage:
-        'The default is three shingle subfields. More subfields enables more specific queries, but increases index size.',
+        'The default is three shingle subfields. More subfields enable more specific queries, but increase index size.',
     })}
     defaultToggleValue={defaultToggleValue}
   >

From 5e1c0be501b672174b2553dbca74d4eba16295f6 Mon Sep 17 00:00:00 2001
From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com>
Date: Thu, 9 Apr 2020 11:56:03 -0400
Subject: [PATCH 26/78] [Endpoint] Add link to Logs UI to the Host Details view
 (#62852)

* Add LinktoApp to host details for logs

* initial setup for testing link on details

* Export interface AppContextTestRender for reference in tests

* Refactor hosts tests to use AppContextTestRender

* Render full details and validate link to logs

* one more test to ensure we navigate to app (not full page refresh)

* Fixes post master merge
---
 .../endpoint/components/link_to_app.tsx       |   2 +-
 .../endpoint/mocks/app_context_render.tsx     |   2 +-
 .../store/hosts/mock_host_result_list.ts      |  13 ++-
 .../endpoint/view/hosts/details.tsx           |  28 +++++
 .../endpoint/view/hosts/index.test.tsx        | 106 +++++++++++++-----
 5 files changed, 119 insertions(+), 32 deletions(-)

diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx
index b110d32442c2c..858dac864b58a 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx
@@ -12,7 +12,7 @@ import { useNavigateToAppEventHandler } from '../hooks/use_navigate_to_app_event
 export type LinkToAppProps = EuiLinkProps & {
   /** the app id - normally the value of the `id` in that plugin's `kibana.json`  */
   appId: string;
-  /** Any app specic path (route) */
+  /** Any app specific path (route) */
   appPath?: string;
   appState?: any;
   onClick?: MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/mocks/app_context_render.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/mocks/app_context_render.tsx
index af34205e2310f..7cb1031ef9a09 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/mocks/app_context_render.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/mocks/app_context_render.tsx
@@ -18,7 +18,7 @@ type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResul
 /**
  * Mocked app root context renderer
  */
-interface AppContextTestRender {
+export interface AppContextTestRender {
   store: ReturnType<typeof appStoreFactory>;
   history: ReturnType<typeof createMemoryHistory>;
   coreStart: ReturnType<typeof coreMock.createStart>;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/mock_host_result_list.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/mock_host_result_list.ts
index d4c2602e34387..20aa973ffc93d 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/mock_host_result_list.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/mock_host_result_list.ts
@@ -4,7 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { HostResultList, HostStatus } from '../../../../../common/types';
+import { HostInfo, HostResultList, HostStatus } from '../../../../../common/types';
 import { EndpointDocGenerator } from '../../../../../common/generate_data';
 
 export const mockHostResultList: (options?: {
@@ -40,3 +40,14 @@ export const mockHostResultList: (options?: {
   };
   return mock;
 };
+
+/**
+ * returns a mocked API response for retrieving a single host metadata
+ */
+export const mockHostDetailsApiResult = (): HostInfo => {
+  const generator = new EndpointDocGenerator('seed');
+  return {
+    metadata: generator.generateHostMetadata(),
+    host_status: HostStatus.ERROR,
+  };
+};
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx
index 37080e8568350..90829f7ad4cbe 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx
@@ -28,6 +28,7 @@ import { useHostListSelector } from './hooks';
 import { urlFromQueryParams } from './url_from_query_params';
 import { FormattedDateAndTime } from '../formatted_date_time';
 import { uiQueryParams, detailsData, detailsError } from './../../store/hosts/selectors';
+import { LinkToApp } from '../../components/link_to_app';
 
 const HostIds = styled(EuiListGroupItem)`
   margin-top: 0;
@@ -37,6 +38,7 @@ const HostIds = styled(EuiListGroupItem)`
 `;
 
 const HostDetails = memo(({ details }: { details: HostMetadata }) => {
+  const { appId, appPath, url } = useHostLogsUrl(details.host.id);
   const detailsResultsUpper = useMemo(() => {
     return [
       {
@@ -113,6 +115,20 @@ const HostDetails = memo(({ details }: { details: HostMetadata }) => {
         listItems={detailsResultsLower}
         data-test-subj="hostDetailsLowerList"
       />
+      <EuiHorizontalRule margin="s" />
+      <p>
+        <LinkToApp
+          appId={appId}
+          appPath={appPath}
+          href={url}
+          data-test-subj="hostDetailsLinkToLogs"
+        >
+          <FormattedMessage
+            id="xpack.endpoint.host.details.linkToLogsTitle"
+            defaultMessage="Endpoint Logs"
+          />
+        </LinkToApp>
+      </p>
     </>
   );
 });
@@ -170,3 +186,15 @@ export const HostDetailsFlyout = () => {
     </EuiFlyout>
   );
 };
+
+const useHostLogsUrl = (hostId: string): { url: string; appId: string; appPath: string } => {
+  const { services } = useKibana();
+  return useMemo(() => {
+    const appPath = `/stream?logFilter=(expression:'host.id:${hostId}',kind:kuery)`;
+    return {
+      url: `${services.application.getUrlForApp('logs')}${appPath}`,
+      appId: 'logs',
+      appPath,
+    };
+  }, [hostId, services.application]);
+};
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx
index f6dfae99c1b11..c3ff41268e3db 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx
@@ -6,40 +6,26 @@
 
 import React from 'react';
 import * as reactTestingLibrary from '@testing-library/react';
-import { Provider } from 'react-redux';
-import { I18nProvider } from '@kbn/i18n/react';
-import { EuiThemeProvider } from '../../../../../../../legacy/common/eui_styled_components';
-import { appStoreFactory } from '../../store';
-import { RouteCapture } from '../route_capture';
-import { createMemoryHistory, MemoryHistory } from 'history';
-import { Router } from 'react-router-dom';
+import { fireEvent } from '@testing-library/react';
 import { AppAction } from '../../types';
 import { HostList } from './index';
-import { mockHostResultList } from '../../store/hosts/mock_host_result_list';
+import {
+  mockHostDetailsApiResult,
+  mockHostResultList,
+} from '../../store/hosts/mock_host_result_list';
+import { AppContextTestRender, createAppRootMockRenderer } from '../../mocks';
+import { HostInfo } from '../../../../../common/types';
 
 describe('when on the hosts page', () => {
-  let render: () => reactTestingLibrary.RenderResult;
-  let history: MemoryHistory<never>;
-  let store: ReturnType<typeof appStoreFactory>;
+  let render: () => ReturnType<AppContextTestRender['render']>;
+  let history: AppContextTestRender['history'];
+  let store: AppContextTestRender['store'];
+  let coreStart: AppContextTestRender['coreStart'];
 
   beforeEach(async () => {
-    history = createMemoryHistory<never>();
-    store = appStoreFactory();
-    render = () => {
-      return reactTestingLibrary.render(
-        <Provider store={store}>
-          <I18nProvider>
-            <EuiThemeProvider>
-              <Router history={history}>
-                <RouteCapture>
-                  <HostList />
-                </RouteCapture>
-              </Router>
-            </EuiThemeProvider>
-          </I18nProvider>
-        </Provider>
-      );
-    };
+    const mockedContext = createAppRootMockRenderer();
+    ({ history, store, coreStart } = mockedContext);
+    render = () => mockedContext.render(<HostList />);
   });
 
   it('should show a table', async () => {
@@ -56,7 +42,7 @@ describe('when on the hosts page', () => {
         expect(e).not.toBeNull();
       });
     });
-    describe('when data loads', () => {
+    describe('when list data loads', () => {
       beforeEach(() => {
         reactTestingLibrary.act(() => {
           const action: AppAction = {
@@ -76,6 +62,16 @@ describe('when on the hosts page', () => {
       describe('when the user clicks the hostname in the table', () => {
         let renderResult: reactTestingLibrary.RenderResult;
         beforeEach(async () => {
+          const hostDetailsApiResponse = mockHostDetailsApiResult();
+
+          coreStart.http.get.mockReturnValue(Promise.resolve(hostDetailsApiResponse));
+          reactTestingLibrary.act(() => {
+            store.dispatch({
+              type: 'serverReturnedHostDetails',
+              payload: hostDetailsApiResponse,
+            });
+          });
+
           renderResult = render();
           const detailsLink = await renderResult.findByTestId('hostnameCellLink');
           if (detailsLink) {
@@ -93,19 +89,71 @@ describe('when on the hosts page', () => {
   });
 
   describe('when there is a selected host in the url', () => {
+    let hostDetails: HostInfo;
     beforeEach(() => {
+      const {
+        host_status,
+        metadata: { host, ...details },
+      } = mockHostDetailsApiResult();
+      hostDetails = {
+        host_status,
+        metadata: {
+          ...details,
+          host: {
+            ...host,
+            id: '1',
+          },
+        },
+      };
+
+      coreStart.http.get.mockReturnValue(Promise.resolve(hostDetails));
+      coreStart.application.getUrlForApp.mockReturnValue('/app/logs');
+
       reactTestingLibrary.act(() => {
         history.push({
           ...history.location,
           search: '?selected_host=1',
         });
       });
+      reactTestingLibrary.act(() => {
+        store.dispatch({
+          type: 'serverReturnedHostDetails',
+          payload: hostDetails,
+        });
+      });
     });
+    afterEach(() => {
+      jest.clearAllMocks();
+    });
+
     it('should show the flyout', () => {
       const renderResult = render();
       return renderResult.findByTestId('hostDetailsFlyout').then(flyout => {
         expect(flyout).not.toBeNull();
       });
     });
+    it('should include the link to logs', async () => {
+      const renderResult = render();
+      const linkToLogs = await renderResult.findByTestId('hostDetailsLinkToLogs');
+      expect(linkToLogs).not.toBeNull();
+      expect(linkToLogs.textContent).toEqual('Endpoint Logs');
+      expect(linkToLogs.getAttribute('href')).toEqual(
+        "/app/logs/stream?logFilter=(expression:'host.id:1',kind:kuery)"
+      );
+    });
+    describe('when link to logs is clicked', () => {
+      beforeEach(async () => {
+        const renderResult = render();
+        const linkToLogs = await renderResult.findByTestId('hostDetailsLinkToLogs');
+        reactTestingLibrary.act(() => {
+          fireEvent.click(linkToLogs);
+        });
+      });
+
+      it('should navigate to logs without full page refresh', async () => {
+        // FIXME: this is not working :(
+        expect(coreStart.application.navigateToApp.mock.calls).toHaveLength(1);
+      });
+    });
   });
 });

From 0dd89e388d3a0d87e7ea07be74b706db234c1c26 Mon Sep 17 00:00:00 2001
From: Nathan Reese <reese.nathan@gmail.com>
Date: Thu, 9 Apr 2020 09:56:11 -0600
Subject: [PATCH 27/78] [Maps] create NOT EXISTS filter for tooltip property
 with no value (#62849)

* [Maps] create NOT EXISTS filter for tooltip property with no value

* review feedback
---
 .../tooltips/es_tooltip_property.test.ts      | 105 ++++++++++++++++++
 .../layers/tooltips/es_tooltip_property.ts    |  19 +++-
 .../layers/tooltips/join_tooltip_property.ts  |   4 +-
 .../layers/tooltips/tooltip_property.ts       |   6 +-
 4 files changed, 125 insertions(+), 9 deletions(-)
 create mode 100644 x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.test.ts

diff --git a/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.test.ts b/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.test.ts
new file mode 100644
index 0000000000000..2cc9e1513719b
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.test.ts
@@ -0,0 +1,105 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { IFieldType, IndexPattern } from '../../../../../../src/plugins/data/public';
+import { ESTooltipProperty } from './es_tooltip_property';
+import { TooltipProperty } from './tooltip_property';
+import { AbstractField } from '../fields/field';
+import { FIELD_ORIGIN } from '../../../common/constants';
+
+class MockField extends AbstractField {}
+
+const indexPatternField = {
+  name: 'machine.os',
+  type: 'string',
+  esTypes: ['text'],
+  count: 0,
+  scripted: false,
+  searchable: true,
+  aggregatable: true,
+  readFromDocValues: false,
+} as IFieldType;
+
+const featurePropertyField = new MockField({
+  fieldName: 'machine.os',
+  origin: FIELD_ORIGIN.SOURCE,
+});
+
+const indexPattern = {
+  id: 'indexPatternId',
+  fields: {
+    getByName: (name: string): IFieldType | null => {
+      return name === 'machine.os' ? indexPatternField : null;
+    },
+  },
+  title: 'my index pattern',
+} as IndexPattern;
+
+describe('getESFilters', () => {
+  test('Should return empty array when field does not exist in index pattern', async () => {
+    const notFoundFeaturePropertyField = new MockField({
+      fieldName: 'field name that is not in index pattern',
+      origin: FIELD_ORIGIN.SOURCE,
+    });
+    const esTooltipProperty = new ESTooltipProperty(
+      new TooltipProperty(
+        notFoundFeaturePropertyField.getName(),
+        await notFoundFeaturePropertyField.getLabel(),
+        'my value'
+      ),
+      indexPattern,
+      notFoundFeaturePropertyField
+    );
+    expect(await esTooltipProperty.getESFilters()).toEqual([]);
+  });
+
+  test('Should return phrase filter when field value is provided', async () => {
+    const esTooltipProperty = new ESTooltipProperty(
+      new TooltipProperty(
+        featurePropertyField.getName(),
+        await featurePropertyField.getLabel(),
+        'my value'
+      ),
+      indexPattern,
+      featurePropertyField
+    );
+    expect(await esTooltipProperty.getESFilters()).toEqual([
+      {
+        meta: {
+          index: 'indexPatternId',
+        },
+        query: {
+          match_phrase: {
+            ['machine.os']: 'my value',
+          },
+        },
+      },
+    ]);
+  });
+
+  test('Should return NOT exists filter for null values', async () => {
+    const esTooltipProperty = new ESTooltipProperty(
+      new TooltipProperty(
+        featurePropertyField.getName(),
+        await featurePropertyField.getLabel(),
+        undefined
+      ),
+      indexPattern,
+      featurePropertyField
+    );
+    expect(await esTooltipProperty.getESFilters()).toEqual([
+      {
+        meta: {
+          index: 'indexPatternId',
+          negate: true,
+        },
+        exists: {
+          field: 'machine.os',
+        },
+      },
+    ]);
+  });
+});
diff --git a/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.ts b/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.ts
index 5c35009881920..d2fdcfaab476c 100644
--- a/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.ts
+++ b/x-pack/plugins/maps/public/layers/tooltips/es_tooltip_property.ts
@@ -7,8 +7,12 @@
 import _ from 'lodash';
 import { ITooltipProperty } from './tooltip_property';
 import { IField } from '../fields/field';
-import { esFilters, IFieldType, IndexPattern } from '../../../../../../src/plugins/data/public';
-import { PhraseFilter } from '../../../../../../src/plugins/data/public';
+import {
+  esFilters,
+  Filter,
+  IFieldType,
+  IndexPattern,
+} from '../../../../../../src/plugins/data/public';
 
 export class ESTooltipProperty implements ITooltipProperty {
   private readonly _tooltipProperty: ITooltipProperty;
@@ -64,12 +68,19 @@ export class ESTooltipProperty implements ITooltipProperty {
     );
   }
 
-  async getESFilters(): Promise<PhraseFilter[]> {
+  async getESFilters(): Promise<Filter[]> {
     const indexPatternField = this._getIndexPatternField();
     if (!indexPatternField) {
       return [];
     }
 
-    return [esFilters.buildPhraseFilter(indexPatternField, this.getRawValue(), this._indexPattern)];
+    const value = this.getRawValue();
+    if (value == null) {
+      const existsFilter = esFilters.buildExistsFilter(indexPatternField, this._indexPattern);
+      existsFilter.meta.negate = true;
+      return [existsFilter];
+    } else {
+      return [esFilters.buildPhraseFilter(indexPatternField, value, this._indexPattern)];
+    }
   }
 }
diff --git a/x-pack/plugins/maps/public/layers/tooltips/join_tooltip_property.ts b/x-pack/plugins/maps/public/layers/tooltips/join_tooltip_property.ts
index 4af236f6e9e36..cc95c12ef630f 100644
--- a/x-pack/plugins/maps/public/layers/tooltips/join_tooltip_property.ts
+++ b/x-pack/plugins/maps/public/layers/tooltips/join_tooltip_property.ts
@@ -6,7 +6,7 @@
 
 import { ITooltipProperty } from './tooltip_property';
 import { IJoin } from '../joins/join';
-import { PhraseFilter } from '../../../../../../src/plugins/data/public';
+import { Filter } from '../../../../../../src/plugins/data/public';
 
 export class JoinTooltipProperty implements ITooltipProperty {
   private readonly _tooltipProperty: ITooltipProperty;
@@ -37,7 +37,7 @@ export class JoinTooltipProperty implements ITooltipProperty {
     return this._tooltipProperty.getHtmlDisplayValue();
   }
 
-  async getESFilters(): Promise<PhraseFilter[]> {
+  async getESFilters(): Promise<Filter[]> {
     const esFilters = [];
     if (this._tooltipProperty.isFilterable()) {
       esFilters.push(...(await this._tooltipProperty.getESFilters()));
diff --git a/x-pack/plugins/maps/public/layers/tooltips/tooltip_property.ts b/x-pack/plugins/maps/public/layers/tooltips/tooltip_property.ts
index 7d680dfe9cae0..8da2ed795943b 100644
--- a/x-pack/plugins/maps/public/layers/tooltips/tooltip_property.ts
+++ b/x-pack/plugins/maps/public/layers/tooltips/tooltip_property.ts
@@ -5,7 +5,7 @@
  */
 
 import _ from 'lodash';
-import { PhraseFilter } from '../../../../../../src/plugins/data/public';
+import { Filter } from '../../../../../../src/plugins/data/public';
 import { TooltipFeature } from '../../../../../plugins/maps/common/descriptor_types';
 
 export interface ITooltipProperty {
@@ -14,7 +14,7 @@ export interface ITooltipProperty {
   getHtmlDisplayValue(): string;
   getRawValue(): string | undefined;
   isFilterable(): boolean;
-  getESFilters(): Promise<PhraseFilter[]>;
+  getESFilters(): Promise<Filter[]>;
 }
 
 export interface LoadFeatureProps {
@@ -70,7 +70,7 @@ export class TooltipProperty implements ITooltipProperty {
     return false;
   }
 
-  async getESFilters(): Promise<PhraseFilter[]> {
+  async getESFilters(): Promise<Filter[]> {
     return [];
   }
 }

From dfea62187f0e1984a50c9cff0c367f31b8728083 Mon Sep 17 00:00:00 2001
From: Maryia Lapata <mary.lopato@gmail.com>
Date: Thu, 9 Apr 2020 18:56:36 +0300
Subject: [PATCH 28/78] [NP] Inline buildPointSeriesData and
 buildHierarchicalData dependencies (#61575)

* Move buildHierarchicalData to vislib

* Move shortened version of buildPointSeriesData to Discover

* Move buildPointSeriesData to vis_type_vislib

* Convert unit tests to jest

* Remove ui/agg_response

* Convert point_series files to TS

* Update TS in unit tests

* Convert buildHierarchicalData to TS

* Convert buildPointSeriesData to TS in Discover

* Clean TS in Discover

* Update TS for buildHierarchicalData

* Update buildHierarchicalData unit tests

* Clean up TS in point_series

* Add unit tests fro response_handler.js

* Simplify point_series for Discover

* Return array for data

* Add check for empty row

* Simplify point_series for Discover

* Return all points

* Specify TS

* Refactoring

* Simplifying

* improve types

* Update _get_point.test.ts

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Joe Reuter <johannes.reuter@elastic.co>
---
 .../kibana/public/discover/kibana_services.ts |   2 -
 .../np_ready/angular/directives/histogram.tsx |  14 +-
 .../np_ready/angular/helpers/index.ts}        |   0
 .../np_ready/angular/helpers/point_series.ts  | 111 +++++++
 .../np_ready/angular/response_handler.js      |   3 +-
 .../core_plugins/kibana/public/kibana.js      |   1 -
 .../vis_type_vislib/public/legacy_imports.ts  |   5 -
 .../vislib/__tests__/response_handlers.js     | 137 ---------
 .../build_hierarchical_data.test.ts}          | 108 ++++---
 .../hierarchical/build_hierarchical_data.ts}  |  50 +++-
 .../public/vislib/helpers/index.ts}           |  13 +-
 .../helpers/point_series/_add_to_siri.test.ts |  84 ++++++
 .../helpers/point_series/_add_to_siri.ts      |  60 ++++
 .../point_series/_fake_x_aspect.test.ts}      |  15 +-
 .../helpers/point_series/_fake_x_aspect.ts}   |   5 +-
 .../point_series/_get_aspects.test.ts}        |  53 ++--
 .../helpers/point_series/_get_aspects.ts}     |  20 +-
 .../helpers/point_series/_get_point.test.ts   | 104 +++++++
 .../helpers/point_series/_get_point.ts}       |  53 +++-
 .../helpers/point_series/_get_series.test.ts  | 281 +++++++++++++++++
 .../helpers/point_series/_get_series.ts       |  88 ++++++
 .../point_series/_init_x_axis.test.ts}        |  91 +++---
 .../helpers/point_series/_init_x_axis.ts}     |  20 +-
 .../point_series/_init_y_axis.test.ts}        |  19 +-
 .../helpers/point_series/_init_y_axis.ts}     |  13 +-
 .../point_series/_ordered_date_axis.test.ts}  |  20 +-
 .../point_series/_ordered_date_axis.ts}       |  10 +-
 .../vislib/helpers/point_series/index.ts}     |  10 +-
 .../point_series/point_series.test.ts}        |  81 ++---
 .../helpers/point_series/point_series.ts      | 118 ++++++++
 .../public/vislib/response_handler.js         |   4 +-
 .../public/vislib/response_handler.test.ts    | 130 ++++++++
 .../vis_type_vislib/public/vislib/types.ts}   |  36 ++-
 .../point_series/__tests__/_add_to_siri.js    |  82 -----
 .../point_series/__tests__/_get_point.js      |  97 ------
 .../point_series/__tests__/_get_series.js     | 283 ------------------
 .../agg_response/point_series/_get_series.js  | 100 -------
 .../agg_response/point_series/point_series.js |  42 ---
 .../dashboard_mode/public/dashboard_viewer.js |   1 -
 .../translations/translations/ja-JP.json      |   2 +-
 .../translations/translations/zh-CN.json      |   2 +-
 41 files changed, 1328 insertions(+), 1040 deletions(-)
 rename src/legacy/{ui/public/agg_response/point_series/index.js => core_plugins/kibana/public/discover/np_ready/angular/helpers/index.ts} (100%)
 create mode 100644 src/legacy/core_plugins/kibana/public/discover/np_ready/angular/helpers/point_series.ts
 delete mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js
 rename src/legacy/{ui/public/agg_response/hierarchical/build_hierarchical_data.test.js => core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts} (80%)
 rename src/legacy/{ui/public/agg_response/hierarchical/build_hierarchical_data.js => core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts} (63%)
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/point_series.js => core_plugins/vis_type_vislib/public/vislib/helpers/index.ts} (71%)
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/_fake_x_aspect.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts} (74%)
 rename src/legacy/{ui/public/agg_response/point_series/_fake_x_aspect.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts} (88%)
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/_get_aspects.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts} (53%)
 rename src/legacy/{ui/public/agg_response/point_series/_get_aspects.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts} (72%)
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts
 rename src/legacy/{ui/public/agg_response/point_series/_get_point.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts} (69%)
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.test.ts
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.ts
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/_init_x_axis.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts} (51%)
 rename src/legacy/{ui/public/agg_response/point_series/_init_x_axis.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.ts} (73%)
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/_init_y_axis.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts} (81%)
 rename src/legacy/{ui/public/agg_response/point_series/_init_y_axis.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.ts} (82%)
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/_ordered_date_axis.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts} (76%)
 rename src/legacy/{ui/public/agg_response/point_series/_ordered_date_axis.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts} (72%)
 rename src/legacy/{ui/public/agg_response/index.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/index.ts} (69%)
 rename src/legacy/{ui/public/agg_response/point_series/__tests__/_main.js => core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts} (62%)
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts
 create mode 100644 src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.test.ts
 rename src/legacy/{ui/public/agg_response/point_series/_add_to_siri.js => core_plugins/vis_type_vislib/public/vislib/types.ts} (67%)
 delete mode 100644 src/legacy/ui/public/agg_response/point_series/__tests__/_add_to_siri.js
 delete mode 100644 src/legacy/ui/public/agg_response/point_series/__tests__/_get_point.js
 delete mode 100644 src/legacy/ui/public/agg_response/point_series/__tests__/_get_series.js
 delete mode 100644 src/legacy/ui/public/agg_response/point_series/_get_series.js
 delete mode 100644 src/legacy/ui/public/agg_response/point_series/point_series.js

diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
index 98679a8f24d16..0a81ca0222b0a 100644
--- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
@@ -76,5 +76,3 @@ export {
   EsQuerySortValue,
   SortDirection,
 } from '../../../../../plugins/data/public';
-// @ts-ignore
-export { buildPointSeriesData } from 'ui/agg_response/point_series/point_series';
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx
index f788347ac016c..8c55622e4c604 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx
@@ -46,9 +46,10 @@ import { IUiSettingsClient } from 'kibana/public';
 import { EuiChartThemeType } from '@elastic/eui/dist/eui_charts_theme';
 import { Subscription } from 'rxjs';
 import { getServices } from '../../../kibana_services';
+import { Chart as IChart } from '../helpers/point_series';
 
 export interface DiscoverHistogramProps {
-  chartData: any;
+  chartData: IChart;
   timefilterUpdateHandler: (ranges: { from: number; to: number }) => void;
 }
 
@@ -163,7 +164,7 @@ export class DiscoverHistogram extends Component<DiscoverHistogramProps, Discove
   };
 
   public formatXValue = (val: string) => {
-    const xAxisFormat = this.props.chartData.xAxisFormat.params.pattern;
+    const xAxisFormat = this.props.chartData.xAxisFormat.params!.pattern;
 
     return moment(val).format(xAxisFormat);
   };
@@ -208,18 +209,19 @@ export class DiscoverHistogram extends Component<DiscoverHistogramProps, Discove
     const { chartData } = this.props;
     const { chartsTheme } = this.state;
 
-    if (!chartData || !chartData.series[0]) {
+    if (!chartData) {
       return null;
     }
 
-    const data = chartData.series[0].values;
+    const data = chartData.values;
 
     /**
      * Deprecation: [interval] on [date_histogram] is deprecated, use [fixed_interval] or [calendar_interval].
      * see https://github.com/elastic/kibana/issues/27410
      * TODO: Once the Discover query has been update, we should change the below to use the new field
      */
-    const { intervalESValue, intervalESUnit, interval: xInterval } = chartData.ordered;
+    const { intervalESValue, intervalESUnit, interval } = chartData.ordered;
+    const xInterval = interval.asMilliseconds();
 
     const xValues = chartData.xAxisOrderedValues;
     const lastXValue = xValues[xValues.length - 1];
@@ -228,7 +230,7 @@ export class DiscoverHistogram extends Component<DiscoverHistogramProps, Discove
     const domainStart = domain.min.valueOf();
     const domainEnd = domain.max.valueOf();
 
-    const domainMin = data[0].x > domainStart ? domainStart : data[0].x;
+    const domainMin = data[0]?.x > domainStart ? domainStart : data[0]?.x;
     const domainMax = domainEnd - xInterval > lastXValue ? domainEnd - xInterval : lastXValue;
 
     const xDomain = {
diff --git a/src/legacy/ui/public/agg_response/point_series/index.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/helpers/index.ts
similarity index 100%
rename from src/legacy/ui/public/agg_response/point_series/index.js
rename to src/legacy/core_plugins/kibana/public/discover/np_ready/angular/helpers/index.ts
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/helpers/point_series.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/helpers/point_series.ts
new file mode 100644
index 0000000000000..02dd024b09812
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/helpers/point_series.ts
@@ -0,0 +1,111 @@
+/*
+ * 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 { uniq } from 'lodash';
+import { Duration, Moment } from 'moment';
+import { Unit } from '@elastic/datemath';
+
+import { SerializedFieldFormat } from '../../../../../../../../plugins/expressions/common/types';
+
+export interface Column {
+  id: string;
+  name: string;
+}
+
+export interface Row {
+  [key: string]: number | 'NaN';
+}
+
+export interface Table {
+  columns: Column[];
+  rows: Row[];
+}
+
+interface HistogramParams {
+  date: true;
+  interval: Duration;
+  intervalESValue: number;
+  intervalESUnit: Unit;
+  format: string;
+  bounds: {
+    min: Moment;
+    max: Moment;
+  };
+}
+export interface Dimension {
+  accessor: 0 | 1;
+  format: SerializedFieldFormat<{ pattern: string }>;
+}
+
+export interface Dimensions {
+  x: Dimension & { params: HistogramParams };
+  y: Dimension;
+}
+
+interface Ordered {
+  date: true;
+  interval: Duration;
+  intervalESUnit: string;
+  intervalESValue: number;
+  min: Moment;
+  max: Moment;
+}
+export interface Chart {
+  values: Array<{
+    x: number;
+    y: number;
+  }>;
+  xAxisOrderedValues: number[];
+  xAxisFormat: Dimension['format'];
+  xAxisLabel: Column['name'];
+  yAxisLabel?: Column['name'];
+  ordered: Ordered;
+}
+
+export const buildPointSeriesData = (table: Table, dimensions: Dimensions) => {
+  const { x, y } = dimensions;
+  const xAccessor = table.columns[x.accessor].id;
+  const yAccessor = table.columns[y.accessor].id;
+  const chart = {} as Chart;
+
+  chart.xAxisOrderedValues = uniq(table.rows.map(r => r[xAccessor] as number));
+  chart.xAxisFormat = x.format;
+  chart.xAxisLabel = table.columns[x.accessor].name;
+
+  const { intervalESUnit, intervalESValue, interval, bounds } = x.params;
+  chart.ordered = {
+    date: true,
+    interval,
+    intervalESUnit,
+    intervalESValue,
+    min: bounds.min,
+    max: bounds.max,
+  };
+
+  chart.yAxisLabel = table.columns[y.accessor].name;
+
+  chart.values = table.rows
+    .filter(row => row && row[yAccessor] !== 'NaN')
+    .map(row => ({
+      x: row[xAccessor] as number,
+      y: row[yAccessor] as number,
+    }));
+
+  return chart;
+};
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/response_handler.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/response_handler.js
index 0c19c10841535..04ccb67ec7e25 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/response_handler.js
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/response_handler.js
@@ -17,7 +17,8 @@
  * under the License.
  */
 
-import { buildPointSeriesData, getServices } from '../../kibana_services';
+import { getServices } from '../../kibana_services';
+import { buildPointSeriesData } from './helpers';
 
 function tableResponseHandler(table, dimensions) {
   const converted = { tables: [] };
diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js
index bceb3fa7eef8a..0a026a5e0c310 100644
--- a/src/legacy/core_plugins/kibana/public/kibana.js
+++ b/src/legacy/core_plugins/kibana/public/kibana.js
@@ -46,7 +46,6 @@ import './discover/legacy';
 import './visualize/legacy';
 import './management';
 import './dev_tools';
-import 'ui/agg_response';
 import { showAppRedirectNotification } from '../../../../plugins/kibana_legacy/public';
 import 'leaflet';
 import { localApplicationService } from './local_application_service';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts
index da16a38deba9f..c04ffa506eb04 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts
@@ -19,8 +19,3 @@
 
 import { search } from '../../../../plugins/data/public';
 export const { tabifyAggResponse, tabifyGetColumns } = search;
-
-// @ts-ignore
-export { buildHierarchicalData } from 'ui/agg_response/hierarchical/build_hierarchical_data';
-// @ts-ignore
-export { buildPointSeriesData } from 'ui/agg_response/point_series/point_series';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js
deleted file mode 100644
index 3574fb232883d..0000000000000
--- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import sinon from 'sinon';
-import ngMock from 'ng_mock';
-import expect from '@kbn/expect';
-
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { aggResponseIndex } from 'ui/agg_response';
-
-import { vislibSeriesResponseHandler } from '../response_handler';
-
-/**
- * TODO: Fix these tests if still needed
- *
- * All these tests were not being run in master or prodiced false positive results
- * Fixing them would require changes to the response handler logic.
- */
-
-describe.skip('Basic Response Handler', function() {
-  beforeEach(ngMock.module('kibana'));
-
-  it('returns empty object if conversion failed', () => {
-    const data = vislibSeriesResponseHandler({});
-    expect(data).to.not.be.an('undefined');
-    expect(data).to.equal({});
-  });
-
-  it('returns empty object if no data was found', () => {
-    const data = vislibSeriesResponseHandler({
-      columns: [{ id: '1', title: '1', aggConfig: {} }],
-      rows: [],
-    });
-    expect(data).to.not.be.an('undefined');
-    expect(data.rows).to.equal([]);
-  });
-});
-
-describe.skip('renderbot#buildChartData', function() {
-  describe('for hierarchical vis', function() {
-    it('defers to hierarchical aggResponse converter', function() {
-      const football = {};
-      const stub = sinon.stub(aggResponseIndex, 'hierarchical').returns(football);
-      expect(vislibSeriesResponseHandler(football)).to.be(football);
-      expect(stub).to.have.property('callCount', 1);
-      expect(stub.firstCall.args[1]).to.be(football);
-    });
-  });
-
-  describe('for point plot', function() {
-    it('calls tabify to simplify the data into a table', function() {
-      const football = { tables: [], hits: { total: 1 } };
-      const stub = sinon.stub(aggResponseIndex, 'tabify').returns(football);
-      expect(vislibSeriesResponseHandler(football)).to.eql({ rows: [], hits: 1 });
-      expect(stub).to.have.property('callCount', 1);
-      expect(stub.firstCall.args[1]).to.be(football);
-    });
-
-    it('returns a single chart if the tabify response contains only a single table', function() {
-      const chart = { hits: 1, rows: [], columns: [] };
-      const esResp = { hits: { total: 1 } };
-      const tabbed = { tables: [{}] };
-
-      sinon.stub(aggResponseIndex, 'tabify').returns(tabbed);
-      expect(vislibSeriesResponseHandler(esResp)).to.eql(chart);
-    });
-
-    it('converts table groups into rows/columns wrappers for charts', function() {
-      const converter = sinon.stub().returns('chart');
-      const esResp = { hits: { total: 1 } };
-      const tables = [{}, {}, {}, {}];
-
-      sinon.stub(aggResponseIndex, 'tabify').returns({
-        tables: [
-          {
-            aggConfig: { params: { row: true } },
-            tables: [
-              {
-                aggConfig: { params: { row: false } },
-                tables: [tables[0]],
-              },
-              {
-                aggConfig: { params: { row: false } },
-                tables: [tables[1]],
-              },
-            ],
-          },
-          {
-            aggConfig: { params: { row: true } },
-            tables: [
-              {
-                aggConfig: { params: { row: false } },
-                tables: [tables[2]],
-              },
-              {
-                aggConfig: { params: { row: false } },
-                tables: [tables[3]],
-              },
-            ],
-          },
-        ],
-      });
-
-      const chartData = vislibSeriesResponseHandler(esResp);
-
-      // verify tables were converted
-      expect(converter).to.have.property('callCount', 4);
-      expect(converter.args[0][1]).to.be(tables[0]);
-      expect(converter.args[1][1]).to.be(tables[1]);
-      expect(converter.args[2][1]).to.be(tables[2]);
-      expect(converter.args[3][1]).to.be(tables[3]);
-
-      expect(chartData).to.have.property('rows');
-      expect(chartData.rows).to.have.length(2);
-      chartData.rows.forEach(function(row) {
-        expect(row).to.have.property('columns');
-        expect(row.columns).to.eql(['chart', 'chart']);
-      });
-    });
-  });
-});
diff --git a/src/legacy/ui/public/agg_response/hierarchical/build_hierarchical_data.test.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts
similarity index 80%
rename from src/legacy/ui/public/agg_response/hierarchical/build_hierarchical_data.test.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts
index 21a937bf1fb66..475555f3a15f3 100644
--- a/src/legacy/ui/public/agg_response/hierarchical/build_hierarchical_data.test.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts
@@ -17,24 +17,26 @@
  * under the License.
  */
 
-import { buildHierarchicalData } from './build_hierarchical_data';
+import { buildHierarchicalData, Dimensions, Dimension } from './build_hierarchical_data';
+import { Table, TableParent } from '../../types';
 
-function tableVisResponseHandler(table, dimensions) {
-  const converted = {
+function tableVisResponseHandler(table: Table, dimensions: Dimensions) {
+  const converted: {
+    tables: Array<TableParent | Table>;
+  } = {
     tables: [],
   };
 
   const split = dimensions.splitColumn || dimensions.splitRow;
 
   if (split) {
-    converted.direction = dimensions.splitRow ? 'row' : 'column';
     const splitColumnIndex = split[0].accessor;
     const splitColumn = table.columns[splitColumnIndex];
-    const splitMap = {};
+    const splitMap: { [key: string]: number } = {};
     let splitIndex = 0;
 
     table.rows.forEach((row, rowIndex) => {
-      const splitValue = row[splitColumn.id];
+      const splitValue = row[splitColumn.id] as string;
 
       if (!splitMap.hasOwnProperty(splitValue)) {
         splitMap[splitValue] = splitIndex++;
@@ -46,8 +48,8 @@ function tableVisResponseHandler(table, dimensions) {
           column: splitColumnIndex,
           row: rowIndex,
           table,
-          tables: [],
-        };
+          tables: [] as Table[],
+        } as any;
 
         tableGroup.tables.push({
           $parent: tableGroup,
@@ -59,34 +61,30 @@ function tableVisResponseHandler(table, dimensions) {
       }
 
       const tableIndex = splitMap[splitValue];
-      converted.tables[tableIndex].tables[0].rows.push(row);
+      (converted.tables[tableIndex] as TableParent).tables![0].rows.push(row);
     });
   } else {
     converted.tables.push({
       columns: table.columns,
       rows: table.rows,
-    });
+    } as Table);
   }
 
   return converted;
 }
 
-jest.mock('ui/new_platform');
-jest.mock('ui/chrome', () => ({
-  getUiSettingsClient: jest.fn().mockReturnValue({
-    get: jest.fn().mockReturnValue('KQL'),
-  }),
-}));
-jest.mock('ui/visualize/loader/pipeline_helpers/utilities', () => ({
-  getFormat: jest.fn(() => ({
-    convert: jest.fn(v => v),
+jest.mock('../../../services', () => ({
+  getFormatService: jest.fn(() => ({
+    deserialize: () => ({
+      convert: jest.fn(v => JSON.stringify(v)),
+    }),
   })),
 }));
 
 describe('buildHierarchicalData convertTable', () => {
   describe('metric only', () => {
-    let dimensions;
-    let table;
+    let dimensions: Dimensions;
+    let table: Table;
 
     beforeEach(() => {
       const tabifyResponse = {
@@ -94,11 +92,11 @@ describe('buildHierarchicalData convertTable', () => {
         rows: [{ 'col-0-agg_1': 412032 }],
       };
       dimensions = {
-        metric: { accessor: 0 },
+        metric: { accessor: 0 } as Dimension,
       };
 
       const tableGroup = tableVisResponseHandler(tabifyResponse, dimensions);
-      table = tableGroup.tables[0];
+      table = tableGroup.tables[0] as Table;
     });
 
     it('should set the slices with one child to a consistent label', () => {
@@ -118,8 +116,8 @@ describe('buildHierarchicalData convertTable', () => {
   });
 
   describe('threeTermBuckets', () => {
-    let dimensions;
-    let tables;
+    let dimensions: Dimensions;
+    let tables: TableParent[];
 
     beforeEach(async () => {
       const tabifyResponse = {
@@ -231,60 +229,60 @@ describe('buildHierarchicalData convertTable', () => {
         ],
       };
       dimensions = {
-        splitRow: [{ accessor: 0 }],
-        metric: { accessor: 5 },
-        buckets: [{ accessor: 2 }, { accessor: 4 }],
+        splitRow: [{ accessor: 0 } as Dimension],
+        metric: { accessor: 5 } as Dimension,
+        buckets: [{ accessor: 2 }, { accessor: 4 }] as Dimension[],
       };
       const tableGroup = await tableVisResponseHandler(tabifyResponse, dimensions);
-      tables = tableGroup.tables;
+      tables = tableGroup.tables as TableParent[];
     });
 
     it('should set the correct hits attribute for each of the results', () => {
       tables.forEach(t => {
-        const results = buildHierarchicalData(t.tables[0], dimensions);
+        const results = buildHierarchicalData(t.tables![0], dimensions);
         expect(results).toHaveProperty('hits');
         expect(results.hits).toBe(4);
       });
     });
 
     it('should set the correct names for each of the results', () => {
-      const results0 = buildHierarchicalData(tables[0].tables[0], dimensions);
+      const results0 = buildHierarchicalData(tables[0].tables![0], dimensions);
       expect(results0).toHaveProperty('names');
       expect(results0.names).toHaveLength(5);
 
-      const results1 = buildHierarchicalData(tables[1].tables[0], dimensions);
+      const results1 = buildHierarchicalData(tables[1].tables![0], dimensions);
       expect(results1).toHaveProperty('names');
       expect(results1.names).toHaveLength(5);
 
-      const results2 = buildHierarchicalData(tables[2].tables[0], dimensions);
+      const results2 = buildHierarchicalData(tables[2].tables![0], dimensions);
       expect(results2).toHaveProperty('names');
       expect(results2.names).toHaveLength(4);
     });
 
     it('should set the parent of the first item in the split', () => {
-      const results0 = buildHierarchicalData(tables[0].tables[0], dimensions);
+      const results0 = buildHierarchicalData(tables[0].tables![0], dimensions);
       expect(results0).toHaveProperty('slices');
       expect(results0.slices).toHaveProperty('children');
       expect(results0.slices.children).toHaveLength(2);
-      expect(results0.slices.children[0].rawData.table.$parent).toHaveProperty('key', 'png');
+      expect(results0.slices.children[0].rawData!.table.$parent).toHaveProperty('key', 'png');
 
-      const results1 = buildHierarchicalData(tables[1].tables[0], dimensions);
+      const results1 = buildHierarchicalData(tables[1].tables![0], dimensions);
       expect(results1).toHaveProperty('slices');
       expect(results1.slices).toHaveProperty('children');
       expect(results1.slices.children).toHaveLength(2);
-      expect(results1.slices.children[0].rawData.table.$parent).toHaveProperty('key', 'css');
+      expect(results1.slices.children[0].rawData!.table.$parent).toHaveProperty('key', 'css');
 
-      const results2 = buildHierarchicalData(tables[2].tables[0], dimensions);
+      const results2 = buildHierarchicalData(tables[2].tables![0], dimensions);
       expect(results2).toHaveProperty('slices');
       expect(results2.slices).toHaveProperty('children');
       expect(results2.slices.children).toHaveLength(2);
-      expect(results2.slices.children[0].rawData.table.$parent).toHaveProperty('key', 'html');
+      expect(results2.slices.children[0].rawData!.table.$parent).toHaveProperty('key', 'html');
     });
   });
 
   describe('oneHistogramBucket', () => {
-    let dimensions;
-    let table;
+    let dimensions: Dimensions;
+    let table: Table;
 
     beforeEach(async () => {
       const tabifyResponse = {
@@ -302,11 +300,11 @@ describe('buildHierarchicalData convertTable', () => {
         ],
       };
       dimensions = {
-        metric: { accessor: 1 },
-        buckets: [{ accessor: 0, params: { field: 'bytes', interval: 8192 } }],
+        metric: { accessor: 1 } as Dimension,
+        buckets: [{ accessor: 0 } as Dimension],
       };
       const tableGroup = await tableVisResponseHandler(tabifyResponse, dimensions);
-      table = tableGroup.tables[0];
+      table = tableGroup.tables[0] as Table;
     });
 
     it('should set the hits attribute for the results', () => {
@@ -320,8 +318,8 @@ describe('buildHierarchicalData convertTable', () => {
   });
 
   describe('oneRangeBucket', () => {
-    let dimensions;
-    let table;
+    let dimensions: Dimensions;
+    let table: Table;
 
     beforeEach(async () => {
       const tabifyResponse = {
@@ -335,11 +333,11 @@ describe('buildHierarchicalData convertTable', () => {
         ],
       };
       dimensions = {
-        metric: { accessor: 1 },
-        buckets: [{ accessor: 0, format: { id: 'range', params: { id: 'agg_2' } } }],
+        metric: { accessor: 1 } as Dimension,
+        buckets: [{ accessor: 0, format: { id: 'range', params: { id: 'agg_2' } } } as Dimension],
       };
       const tableGroup = await tableVisResponseHandler(tabifyResponse, dimensions);
-      table = tableGroup.tables[0];
+      table = tableGroup.tables[0] as Table;
     });
 
     it('should set the hits attribute for the results', () => {
@@ -348,13 +346,13 @@ describe('buildHierarchicalData convertTable', () => {
       expect(results).toHaveProperty('slices');
       expect(results.slices).toHaveProperty('children');
       expect(results).toHaveProperty('names');
-      // expect(results.names).toHaveLength(2);
+      expect(results.names).toHaveLength(2);
     });
   });
 
   describe('oneFilterBucket', () => {
-    let dimensions;
-    let table;
+    let dimensions: Dimensions;
+    let table: Table;
 
     beforeEach(async () => {
       const tabifyResponse = {
@@ -368,15 +366,15 @@ describe('buildHierarchicalData convertTable', () => {
         ],
       };
       dimensions = {
-        metric: { accessor: 1 },
+        metric: { accessor: 1 } as Dimension,
         buckets: [
           {
             accessor: 0,
           },
-        ],
+        ] as Dimension[],
       };
       const tableGroup = await tableVisResponseHandler(tabifyResponse, dimensions);
-      table = tableGroup.tables[0];
+      table = tableGroup.tables[0] as Table;
     });
 
     it('should set the hits attribute for the results', () => {
diff --git a/src/legacy/ui/public/agg_response/hierarchical/build_hierarchical_data.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts
similarity index 63%
rename from src/legacy/ui/public/agg_response/hierarchical/build_hierarchical_data.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts
index dcc27e956b3f8..2c6d62ed084b5 100644
--- a/src/legacy/ui/public/agg_response/hierarchical/build_hierarchical_data.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts
@@ -18,11 +18,41 @@
  */
 
 import { toArray } from 'lodash';
-import { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities';
+import { SerializedFieldFormat } from '../../../../../../../plugins/expressions/common/types';
+import { getFormatService } from '../../../services';
+import { Table } from '../../types';
 
-export const buildHierarchicalData = (table, { metric, buckets = [] }) => {
-  let slices;
-  const names = {};
+export interface Dimension {
+  accessor: number;
+  format: {
+    id?: string;
+    params?: SerializedFieldFormat<object>;
+  };
+}
+
+export interface Dimensions {
+  metric: Dimension;
+  buckets?: Dimension[];
+  splitRow?: Dimension[];
+  splitColumn?: Dimension[];
+}
+
+interface Slice {
+  name: string;
+  size: number;
+  parent?: Slice;
+  children?: [];
+  rawData?: {
+    table: Table;
+    row: number;
+    column: number;
+    value: string | number | object;
+  };
+}
+
+export const buildHierarchicalData = (table: Table, { metric, buckets = [] }: Dimensions) => {
+  let slices: Slice[];
+  const names: { [key: string]: string } = {};
   const metricColumn = table.columns[metric.accessor];
   const metricFieldFormatter = metric.format;
 
@@ -30,25 +60,25 @@ export const buildHierarchicalData = (table, { metric, buckets = [] }) => {
     slices = [
       {
         name: metricColumn.name,
-        size: table.rows[0][metricColumn.id],
+        size: table.rows[0][metricColumn.id] as number,
       },
     ];
     names[metricColumn.name] = metricColumn.name;
   } else {
     slices = [];
     table.rows.forEach((row, rowIndex) => {
-      let parent;
+      let parent: Slice;
       let dataLevel = slices;
 
       buckets.forEach(bucket => {
         const bucketColumn = table.columns[bucket.accessor];
         const bucketValueColumn = table.columns[bucket.accessor + 1];
-        const bucketFormatter = getFormat(bucket.format);
+        const bucketFormatter = getFormatService().deserialize(bucket.format);
         const name = bucketFormatter.convert(row[bucketColumn.id]);
-        const size = row[bucketValueColumn.id];
+        const size = row[bucketValueColumn.id] as number;
         names[name] = name;
 
-        let slice = dataLevel.find(slice => slice.name === name);
+        let slice = dataLevel.find(dataLevelSlice => dataLevelSlice.name === name);
         if (!slice) {
           slice = {
             name,
@@ -66,7 +96,7 @@ export const buildHierarchicalData = (table, { metric, buckets = [] }) => {
         }
 
         parent = slice;
-        dataLevel = slice.children;
+        dataLevel = slice.children as [];
       });
     });
   }
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/point_series.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/index.ts
similarity index 71%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/point_series.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/index.ts
index 9c3e1c8180eb5..90924e79f6027 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/point_series.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/index.ts
@@ -17,14 +17,5 @@
  * under the License.
  */
 
-describe('Point Series Agg Response', function() {
-  require('./_main');
-  require('./_add_to_siri');
-  require('./_fake_x_aspect');
-  require('./_get_aspects');
-  require('./_get_point');
-  require('./_get_series');
-  require('./_init_x_axis');
-  require('./_init_y_axis');
-  require('./_ordered_date_axis');
-});
+export { buildPointSeriesData } from './point_series';
+export { buildHierarchicalData } from './hierarchical/build_hierarchical_data';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts
new file mode 100644
index 0000000000000..e4fdd6bb71c00
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts
@@ -0,0 +1,84 @@
+/*
+ * 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 { addToSiri, Serie } from './_add_to_siri';
+import { Point } from './_get_point';
+import { Dimension } from './point_series';
+
+describe('addToSiri', function() {
+  it('creates a new series the first time it sees an id', function() {
+    const series = new Map<string, Serie>();
+    const point = {} as Point;
+    const id = 'id';
+    addToSiri(series, point, id, id, { id });
+
+    const expectedSerie = series.get(id) as Serie;
+    expect(series.has(id)).toBe(true);
+    expect(expectedSerie).toEqual(expect.any(Object));
+    expect(expectedSerie.label).toBe(id);
+    expect(expectedSerie.values).toHaveLength(1);
+    expect(expectedSerie.values[0]).toBe(point);
+  });
+
+  it('adds points to existing series if id has been seen', function() {
+    const series = new Map();
+    const id = 'id';
+
+    const point = {} as Point;
+    addToSiri(series, point, id, id, { id });
+
+    const point2 = {} as Point;
+    addToSiri(series, point2, id, id, { id });
+
+    expect(series.has(id)).toBe(true);
+    expect(series.get(id)).toEqual(expect.any(Object));
+    expect(series.get(id).label).toBe(id);
+    expect(series.get(id).values).toHaveLength(2);
+    expect(series.get(id).values[0]).toBe(point);
+    expect(series.get(id).values[1]).toBe(point2);
+  });
+
+  it('allows overriding the series label', function() {
+    const series = new Map();
+    const id = 'id';
+    const label = 'label';
+    const point = {} as Point;
+    addToSiri(series, point, id, label, { id });
+
+    expect(series.has(id)).toBe(true);
+    expect(series.get(id)).toEqual(expect.any(Object));
+    expect(series.get(id).label).toBe(label);
+    expect(series.get(id).values).toHaveLength(1);
+    expect(series.get(id).values[0]).toBe(point);
+  });
+
+  it('correctly sets id and rawId', function() {
+    const series = new Map();
+    const id = 'id-id2';
+
+    const point = {} as Point;
+    addToSiri(series, point, id, undefined, {} as Dimension['format']);
+
+    expect(series.has(id)).toBe(true);
+    expect(series.get(id)).toEqual(expect.any(Object));
+    expect(series.get(id).label).toBe(id);
+    expect(series.get(id).rawId).toBe(id);
+    expect(series.get(id).id).toBe('id2');
+  });
+});
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts
new file mode 100644
index 0000000000000..5e5185d6c31ab
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.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 { Point } from './_get_point';
+import { Dimension } from './point_series';
+
+export interface Serie {
+  id: string;
+  rawId: string;
+  label: string;
+  count: number;
+  values: Point[];
+  format: Dimension['format'];
+  zLabel?: string;
+  zFormat?: Dimension['format'];
+}
+
+export function addToSiri(
+  series: Map<string, Serie>,
+  point: Point,
+  id: string,
+  yLabel: string | undefined | null,
+  yFormat: Dimension['format'],
+  zFormat?: Dimension['format'],
+  zLabel?: string
+) {
+  id = id == null ? '' : id + '';
+
+  if (series.has(id)) {
+    (series.get(id) as Serie).values.push(point);
+    return;
+  }
+
+  series.set(id, {
+    id: id.split('-').pop() as string,
+    rawId: id,
+    label: yLabel == null ? id : yLabel,
+    count: 0,
+    values: [point],
+    format: yFormat,
+    zLabel,
+    zFormat,
+  });
+}
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_fake_x_aspect.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts
similarity index 74%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/_fake_x_aspect.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts
index 6c246d7f50897..43d4c3d7ca7c4 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_fake_x_aspect.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts
@@ -16,20 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import expect from '@kbn/expect';
-import { makeFakeXAspect } from '../_fake_x_aspect';
+import { makeFakeXAspect } from './_fake_x_aspect';
 
 describe('makeFakeXAspect', function() {
   it('creates an object that looks like an aspect', function() {
     const aspect = makeFakeXAspect();
 
-    expect(aspect)
-      .to.have.property('accessor', -1)
-      .and.have.property('title', 'All docs')
-      .and.have.property('format')
-      .and.have.property('params');
+    expect(aspect).toHaveProperty('accessor', -1);
+    expect(aspect).toHaveProperty('title', 'All docs');
+    expect(aspect).toHaveProperty('format');
+    expect(aspect).toHaveProperty('params');
 
-    expect(aspect.params).to.have.property('defaultValue', '_all');
+    expect(aspect.params).toHaveProperty('defaultValue', '_all');
   });
 });
diff --git a/src/legacy/ui/public/agg_response/point_series/_fake_x_aspect.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts
similarity index 88%
rename from src/legacy/ui/public/agg_response/point_series/_fake_x_aspect.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts
index 254a42baeddb0..1bffa4cceb5b0 100644
--- a/src/legacy/ui/public/agg_response/point_series/_fake_x_aspect.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts
@@ -18,16 +18,17 @@
  */
 
 import { i18n } from '@kbn/i18n';
+import { Aspect } from './point_series';
 
 export function makeFakeXAspect() {
   return {
     accessor: -1,
-    title: i18n.translate('common.ui.aggResponse.allDocsTitle', {
+    title: i18n.translate('visTypeVislib.aggResponse.allDocsTitle', {
       defaultMessage: 'All docs',
     }),
     params: {
       defaultValue: '_all',
     },
     format: {},
-  };
+  } as Aspect;
 }
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_get_aspects.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts
similarity index 53%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/_get_aspects.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts
index fab5c2e290e7e..450b283abbed2 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_get_aspects.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts
@@ -17,37 +17,37 @@
  * under the License.
  */
 
-import expect from '@kbn/expect';
-import { getAspects } from '../_get_aspects';
+import { getAspects } from './_get_aspects';
+import { Dimension, Dimensions, Aspect } from './point_series';
+import { Table, Row } from '../../types';
 
 describe('getAspects', function() {
-  let table;
-  let dimensions;
+  let table: Table;
+  let dimensions: Dimensions;
 
-  function validate(aspect, i) {
-    expect(aspect)
-      .to.be.an('object')
-      .and.have.property('accessor', i);
+  function validate(aspect: Aspect, i: string) {
+    expect(aspect).toEqual(expect.any(Object));
+    expect(aspect).toHaveProperty('accessor', i);
   }
 
-  function init(group, x, y) {
+  function init(group: number, x: number | null, y: number) {
     table = {
       columns: [
-        { id: '0', title: 'date' }, // date
-        { id: '1', title: 'date utc_time' }, // date
-        { id: '2', title: 'ext' }, // extension
-        { id: '3', title: 'geo.src' }, // extension
-        { id: '4', title: 'count' }, // count
-        { id: '5', title: 'avg bytes' }, // avg
+        { id: '0', name: 'date' }, // date
+        { id: '1', name: 'date utc_time' }, // date
+        { id: '2', name: 'ext' }, // extension
+        { id: '3', name: 'geo.src' }, // extension
+        { id: '4', name: 'count' }, // count
+        { id: '5', name: 'avg bytes' }, // avg
       ],
-      rows: [],
-    };
+      rows: [] as Row[],
+    } as Table;
 
     dimensions = {
-      x: { accessor: x },
-      y: { accessor: y },
-      series: { accessor: group },
-    };
+      x: { accessor: x } as Dimension,
+      y: [{ accessor: y } as Dimension],
+      series: [{ accessor: group } as Dimension],
+    } as Dimensions;
   }
 
   it('produces an aspect object for each of the aspect types found in the columns', function() {
@@ -55,8 +55,8 @@ describe('getAspects', function() {
 
     const aspects = getAspects(table, dimensions);
     validate(aspects.x[0], '0');
-    validate(aspects.series[0], '1');
-    validate(aspects.y[0], '2');
+    validate(aspects.series![0], '1');
+    validate(aspects.y![0], '2');
   });
 
   it('creates a fake x aspect if the column does not exist', function() {
@@ -64,9 +64,8 @@ describe('getAspects', function() {
 
     const aspects = getAspects(table, dimensions);
 
-    expect(aspects.x[0])
-      .to.be.an('object')
-      .and.have.property('accessor', -1)
-      .and.have.property('title');
+    expect(aspects.x[0]).toEqual(expect.any(Object));
+    expect(aspects.x[0]).toHaveProperty('accessor', -1);
+    expect(aspects.x[0]).toHaveProperty('title');
   });
 });
diff --git a/src/legacy/ui/public/agg_response/point_series/_get_aspects.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts
similarity index 72%
rename from src/legacy/ui/public/agg_response/point_series/_get_aspects.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts
index fe74d8566c0e7..29134409ddd5f 100644
--- a/src/legacy/ui/public/agg_response/point_series/_get_aspects.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts
@@ -18,20 +18,22 @@
  */
 
 import { makeFakeXAspect } from './_fake_x_aspect';
+import { Dimensions, Aspects } from './point_series';
+import { Table } from '../../types';
 
 /**
  * Identify and group the columns based on the aspect of the pointSeries
  * they represent.
  *
- * @param  {array} columns - the list of columns
  * @return {object} - an object with a key for each aspect (see map). The values
- *                    may be undefined, a single aspect, or an array of aspects.
+ *                    may be undefined or an array of aspects.
  */
-export function getAspects(table, dimensions) {
-  const aspects = {};
-  Object.keys(dimensions).forEach(name => {
-    const dimension = Array.isArray(dimensions[name]) ? dimensions[name] : [dimensions[name]];
-    dimension.forEach(d => {
+export function getAspects(table: Table, dimensions: Dimensions) {
+  const aspects: Partial<Aspects> = {};
+  (Object.keys(dimensions) as Array<keyof Dimensions>).forEach(name => {
+    const dimension = dimensions[name];
+    const dimensionList = Array.isArray(dimension) ? dimension : [dimension];
+    dimensionList.forEach(d => {
       if (!d) {
         return;
       }
@@ -42,7 +44,7 @@ export function getAspects(table, dimensions) {
       if (!aspects[name]) {
         aspects[name] = [];
       }
-      aspects[name].push({
+      aspects[name]!.push({
         accessor: column.id,
         column: d.accessor,
         title: column.name,
@@ -56,5 +58,5 @@ export function getAspects(table, dimensions) {
     aspects.x = [makeFakeXAspect()];
   }
 
-  return aspects;
+  return aspects as Aspects;
 }
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts
new file mode 100644
index 0000000000000..0c79c5b263cea
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts
@@ -0,0 +1,104 @@
+/*
+ * 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 { IFieldFormatsRegistry } from '../../../../../../../plugins/data/common';
+import { getPoint } from './_get_point';
+import { setFormatService } from '../../../services';
+import { Aspect } from './point_series';
+import { Table, Row, Column } from '../../types';
+
+describe('getPoint', function() {
+  let deserialize: IFieldFormatsRegistry['deserialize'];
+
+  beforeAll(() => {
+    deserialize = jest.fn(() => ({
+      convert: jest.fn(v => v),
+    })) as any;
+
+    setFormatService({
+      deserialize,
+    } as any);
+  });
+
+  const table = {
+    columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+    rows: [
+      { '0': 1, '1': 2, '2': 3 },
+      { '0': 4, '1': 'NaN', '2': 6 },
+    ],
+  } as Table;
+
+  describe('Without series aspect', function() {
+    let seriesAspect: undefined;
+    let xAspect: Aspect;
+    let yAspect: Aspect;
+
+    beforeEach(function() {
+      xAspect = { accessor: '0' } as Aspect;
+      yAspect = { accessor: '1', title: 'Y' } as Aspect;
+    });
+
+    it('properly unwraps values', function() {
+      const row = table.rows[0];
+      const zAspect = { accessor: '2' } as Aspect;
+      const point = getPoint(table, xAspect, seriesAspect, row, 0, yAspect, zAspect);
+
+      expect(point).toHaveProperty('x', 1);
+      expect(point).toHaveProperty('y', 2);
+      expect(point).toHaveProperty('z', 3);
+      expect(point).toHaveProperty('series', yAspect.title);
+    });
+
+    it('ignores points with a y value of NaN', function() {
+      const row = table.rows[1];
+      const point = getPoint(table, xAspect, seriesAspect, row, 1, yAspect);
+      expect(point).toBe(void 0);
+    });
+  });
+
+  describe('With series aspect', function() {
+    let row: Row;
+    let xAspect: Aspect;
+    let yAspect: Aspect;
+
+    beforeEach(function() {
+      row = table.rows[0];
+      xAspect = { accessor: '0' } as Aspect;
+      yAspect = { accessor: '2' } as Aspect;
+    });
+
+    it('properly unwraps values', function() {
+      const seriesAspect = [{ accessor: '1' } as Aspect];
+      const point = getPoint(table, xAspect, seriesAspect, row, 0, yAspect);
+
+      expect(point).toHaveProperty('x', 1);
+      expect(point).toHaveProperty('series', '2');
+      expect(point).toHaveProperty('y', 3);
+    });
+
+    it('should call deserialize', function() {
+      const seriesAspect = [
+        { accessor: '1', format: { id: 'number', params: { pattern: '$' } } } as Aspect,
+      ];
+      getPoint(table, xAspect, seriesAspect, row, 0, yAspect);
+
+      expect(deserialize).toHaveBeenCalledWith(seriesAspect[0].format);
+    });
+  });
+});
diff --git a/src/legacy/ui/public/agg_response/point_series/_get_point.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts
similarity index 69%
rename from src/legacy/ui/public/agg_response/point_series/_get_point.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts
index 11e639f3f54a8..3fc13eb0c04b5 100644
--- a/src/legacy/ui/public/agg_response/point_series/_get_point.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts
@@ -17,19 +17,55 @@
  * under the License.
  */
 
-import { getFormat } from '../../visualize/loader/pipeline_helpers/utilities';
+import { getFormatService } from '../../../services';
+import { Aspect } from './point_series';
+import { Table, Row } from '../../types';
 
-export function getPoint(table, x, series, yScale, row, rowIndex, y, z) {
+type RowValue = number | string | object | 'NaN';
+interface Raw {
+  table: Table;
+  column: number | undefined;
+  row: number | undefined;
+  value?: RowValue;
+}
+export interface Point {
+  x: RowValue | '_all';
+  y: RowValue;
+  z?: RowValue;
+  extraMetrics: [];
+  seriesRaw?: Raw;
+  xRaw: Raw;
+  yRaw: Raw;
+  zRaw?: Raw;
+  tableRaw?: {
+    table: Table;
+    column: number;
+    row: number;
+    value: number;
+    title: string;
+  };
+  parent: Aspect | null;
+  series?: string;
+  seriesId?: string;
+}
+export function getPoint(
+  table: Table,
+  x: Aspect,
+  series: Aspect[] | undefined,
+  row: Row,
+  rowIndex: number,
+  y: Aspect,
+  z?: Aspect
+): Point | undefined {
   const xRow = x.accessor === -1 ? '_all' : row[x.accessor];
   const yRow = row[y.accessor];
   const zRow = z && row[z.accessor];
 
-  const point = {
+  const point: Point = {
     x: xRow,
     y: yRow,
     z: zRow,
     extraMetrics: [],
-    yScale: yScale,
     seriesRaw: series && {
       table,
       column: series[0].column,
@@ -71,10 +107,9 @@ export function getPoint(table, x, series, yScale, row, rowIndex, y, z) {
   }
 
   if (series) {
-    const seriesArray = series.length ? series : [series];
-    point.series = seriesArray
+    point.series = series
       .map(s => {
-        const fieldFormatter = getFormat(s.format);
+        const fieldFormatter = getFormatService().deserialize(s.format);
         return fieldFormatter.convert(row[s.accessor]);
       })
       .join(' - ');
@@ -84,9 +119,5 @@ export function getPoint(table, x, series, yScale, row, rowIndex, y, z) {
     point.series = y.title;
   }
 
-  if (yScale) {
-    point.y *= yScale;
-  }
-
   return point;
 }
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.test.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.test.ts
new file mode 100644
index 0000000000000..6b94b9de8e15f
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.test.ts
@@ -0,0 +1,281 @@
+/*
+ * 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 { getSeries } from './_get_series';
+import { setFormatService } from '../../../services';
+import { Chart, Aspect } from './point_series';
+import { Table, Column } from '../../types';
+import { Serie } from './_add_to_siri';
+import { Point } from './_get_point';
+
+describe('getSeries', function() {
+  beforeAll(() => {
+    setFormatService({
+      deserialize: () => ({
+        convert: jest.fn(v => v),
+      }),
+    } as any);
+  });
+
+  it('produces a single series with points for each row', function() {
+    const table = {
+      columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+      rows: [
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+      ],
+    } as Table;
+
+    const chart = {
+      aspects: {
+        x: [{ accessor: '0' }],
+        y: [{ accessor: '1', title: 'y' }],
+        z: [{ accessor: '2' }],
+      },
+    } as Chart;
+
+    const series = getSeries(table, chart);
+
+    expect(series).toEqual(expect.any(Array));
+    expect(series).toHaveLength(1);
+
+    const siri = series[0];
+
+    expect(siri).toEqual(expect.any(Object));
+    expect(siri).toHaveProperty('label', chart.aspects.y[0].title);
+    expect(siri).toHaveProperty('values');
+
+    expect(siri.values).toEqual(expect.any(Array));
+    expect(siri.values).toHaveLength(5);
+
+    siri.values.forEach(point => {
+      expect(point).toHaveProperty('x', 1);
+      expect(point).toHaveProperty('y', 2);
+      expect(point).toHaveProperty('z', 3);
+    });
+  });
+
+  it('adds the seriesId to each point', function() {
+    const table = {
+      columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+      rows: [
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+      ],
+    } as Table;
+
+    const chart = {
+      aspects: {
+        x: [{ accessor: '0' }],
+        y: [
+          { accessor: '1', title: '0' },
+          { accessor: '2', title: '1' },
+        ],
+      },
+    } as Chart;
+
+    const series = getSeries(table, chart);
+
+    series[0].values.forEach(point => {
+      expect(point).toHaveProperty('seriesId', '1');
+    });
+
+    series[1].values.forEach(point => {
+      expect(point).toHaveProperty('seriesId', '2');
+    });
+  });
+
+  it('produces multiple series if there are multiple y aspects', function() {
+    const table = {
+      columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+      rows: [
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+      ],
+    } as Table;
+
+    const chart = {
+      aspects: {
+        x: [{ accessor: '0' }],
+        y: [
+          { accessor: '1', title: '0' },
+          { accessor: '2', title: '1' },
+        ],
+      },
+    } as Chart;
+
+    const series = getSeries(table, chart);
+
+    expect(series).toEqual(expect.any(Array));
+    expect(series).toHaveLength(2);
+
+    series.forEach(function(siri: Serie, i: number) {
+      expect(siri).toEqual(expect.any(Object));
+      expect(siri).toHaveProperty('label', '' + i);
+      expect(siri).toHaveProperty('values');
+
+      expect(siri.values).toEqual(expect.any(Array));
+      expect(siri.values).toHaveLength(5);
+
+      siri.values.forEach(function(point: Point) {
+        expect(point).toHaveProperty('x', 1);
+        expect(point).toHaveProperty('y', i + 2);
+      });
+    });
+  });
+
+  it('produces multiple series if there is a series aspect', function() {
+    const table = {
+      columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+      rows: [
+        { '0': 0, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 0, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 0, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+      ],
+    } as Table;
+
+    const chart = {
+      aspects: {
+        x: [{ accessor: -1 } as Aspect],
+        series: [{ accessor: '0' }],
+        y: [{ accessor: '1', title: '0' }],
+      },
+    } as Chart;
+
+    const series = getSeries(table, chart);
+
+    expect(series).toEqual(expect.any(Array));
+    expect(series).toHaveLength(2);
+
+    series.forEach(function(siri: Serie, i: number) {
+      expect(siri).toEqual(expect.any(Object));
+      expect(siri).toHaveProperty('label', '' + i);
+      expect(siri).toHaveProperty('values');
+
+      expect(siri.values).toEqual(expect.any(Array));
+      expect(siri.values).toHaveLength(3);
+
+      siri.values.forEach(function(point: Point) {
+        expect(point).toHaveProperty('y', 2);
+      });
+    });
+  });
+
+  it('produces multiple series if there is a series aspect and multiple y aspects', function() {
+    const table = {
+      columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+      rows: [
+        { '0': 0, '1': 3, '2': 4 },
+        { '0': 1, '1': 3, '2': 4 },
+        { '0': 0, '1': 3, '2': 4 },
+        { '0': 1, '1': 3, '2': 4 },
+        { '0': 0, '1': 3, '2': 4 },
+        { '0': 1, '1': 3, '2': 4 },
+      ],
+    } as Table;
+
+    const chart = {
+      aspects: {
+        x: [{ accessor: -1 } as Aspect],
+        series: [{ accessor: '0' }],
+        y: [
+          { accessor: '1', title: '0' },
+          { accessor: '2', title: '1' },
+        ],
+      },
+    } as Chart;
+
+    const series = getSeries(table, chart);
+
+    expect(series).toEqual(expect.any(Array));
+    expect(series).toHaveLength(4); // two series * two metrics
+
+    checkSiri(series[0], '0: 0', 3);
+    checkSiri(series[1], '0: 1', 4);
+    checkSiri(series[2], '1: 0', 3);
+    checkSiri(series[3], '1: 1', 4);
+
+    function checkSiri(siri: Serie, label: string, y: number) {
+      expect(siri).toEqual(expect.any(Object));
+      expect(siri).toHaveProperty('label', label);
+      expect(siri).toHaveProperty('values');
+
+      expect(siri.values).toEqual(expect.any(Array));
+      expect(siri.values).toHaveLength(3);
+
+      siri.values.forEach(function(point: Point) {
+        expect(point).toHaveProperty('y', y);
+      });
+    }
+  });
+
+  it('produces a series list in the same order as its corresponding metric column', function() {
+    const table = {
+      columns: [{ id: '0' }, { id: '1' }, { id: '3' }] as Column[],
+      rows: [
+        { '0': 0, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 0, '1': 2, '2': 3 },
+        { '0': 1, '1': 2, '2': 3 },
+        { '0': 0, '1': 2, '2': 3 },
+      ],
+    } as Table;
+
+    const chart = {
+      aspects: {
+        x: [{ accessor: -1 } as Aspect],
+        series: [{ accessor: '0' }],
+        y: [
+          { accessor: '1', title: '0' },
+          { accessor: '2', title: '1' },
+        ],
+      },
+    } as Chart;
+
+    const series = getSeries(table, chart);
+    expect(series[0]).toHaveProperty('label', '0: 0');
+    expect(series[1]).toHaveProperty('label', '0: 1');
+    expect(series[2]).toHaveProperty('label', '1: 0');
+    expect(series[3]).toHaveProperty('label', '1: 1');
+
+    // switch the order of the y columns
+    chart.aspects.y = chart.aspects.y.reverse();
+    chart.aspects.y.forEach(function(y: any, i) {
+      y.i = i;
+    });
+
+    const series2 = getSeries(table, chart);
+    expect(series2[0]).toHaveProperty('label', '0: 1');
+    expect(series2[1]).toHaveProperty('label', '0: 0');
+    expect(series2[2]).toHaveProperty('label', '1: 1');
+    expect(series2[3]).toHaveProperty('label', '1: 0');
+  });
+});
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.ts
new file mode 100644
index 0000000000000..edde5b69af022
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.ts
@@ -0,0 +1,88 @@
+/*
+ * 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 { partial } from 'lodash';
+import { getPoint } from './_get_point';
+import { addToSiri, Serie } from './_add_to_siri';
+import { Chart } from './point_series';
+import { Table } from '../../types';
+
+export function getSeries(table: Table, chart: Chart) {
+  const aspects = chart.aspects;
+  const xAspect = aspects.x[0];
+  const yAspect = aspects.y[0];
+  const zAspect = aspects.z && aspects.z[0];
+  const multiY = Array.isArray(aspects.y) && aspects.y.length > 1;
+
+  const partGetPoint = partial(getPoint, table, xAspect, aspects.series);
+
+  const seriesMap = new Map<string, Serie>();
+
+  table.rows.forEach((row, rowIndex) => {
+    if (!multiY) {
+      const point = partGetPoint(row, rowIndex, yAspect, zAspect);
+      if (point) {
+        const id = `${point.series}-${yAspect.accessor}`;
+        point.seriesId = id;
+        addToSiri(
+          seriesMap,
+          point,
+          id,
+          point.series,
+          yAspect.format,
+          zAspect && zAspect.format,
+          zAspect && zAspect.title
+        );
+      }
+      return;
+    }
+
+    aspects.y.forEach(function(y) {
+      const point = partGetPoint(row, rowIndex, y, zAspect);
+      if (!point) {
+        return;
+      }
+
+      // use the point's y-axis as it's series by default,
+      // but augment that with series aspect if it's actually
+      // available
+      let seriesId = y.accessor;
+      let seriesLabel = y.title;
+
+      if (aspects.series) {
+        const prefix = point.series ? point.series + ': ' : '';
+        seriesId = prefix + seriesId;
+        seriesLabel = prefix + seriesLabel;
+      }
+
+      point.seriesId = seriesId;
+      addToSiri(
+        seriesMap,
+        point,
+        seriesId as string,
+        seriesLabel,
+        y.format,
+        zAspect && zAspect.format,
+        zAspect && zAspect.title
+      );
+    });
+  });
+
+  return [...seriesMap.values()];
+}
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_init_x_axis.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts
similarity index 51%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/_init_x_axis.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts
index a8512edee658b..d3049d7675408 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_init_x_axis.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts
@@ -17,14 +17,22 @@
  * under the License.
  */
 
-import expect from '@kbn/expect';
 import moment from 'moment';
-import { initXAxis } from '../_init_x_axis';
-import { makeFakeXAspect } from '../_fake_x_aspect';
+import { initXAxis } from './_init_x_axis';
+import { makeFakeXAspect } from './_fake_x_aspect';
+import {
+  Aspects,
+  Chart,
+  DateHistogramOrdered,
+  DateHistogramParams,
+  HistogramOrdered,
+  HistogramParams,
+} from './point_series';
+import { Table, Column } from '../../types';
 
 describe('initXAxis', function() {
-  let chart;
-  let table;
+  let chart: Chart;
+  let table: Table;
 
   beforeEach(function() {
     chart = {
@@ -32,50 +40,48 @@ describe('initXAxis', function() {
         x: [
           {
             ...makeFakeXAspect(),
-            accessor: 0,
+            accessor: '0',
             title: 'label',
           },
         ],
-      },
-    };
+      } as Aspects,
+    } as Chart;
 
     table = {
-      columns: [{ id: '0' }],
+      columns: [{ id: '0' } as Column],
       rows: [{ '0': 'hello' }, { '0': 'world' }, { '0': 'foo' }, { '0': 'bar' }, { '0': 'baz' }],
     };
   });
 
   it('sets the xAxisFormatter if the agg is not ordered', function() {
     initXAxis(chart, table);
-    expect(chart)
-      .to.have.property('xAxisLabel', 'label')
-      .and.have.property('xAxisFormat', chart.aspects.x[0].format);
+    expect(chart).toHaveProperty('xAxisLabel', 'label');
+    expect(chart).toHaveProperty('xAxisFormat', chart.aspects.x[0].format);
   });
 
   it('makes the chart ordered if the agg is ordered', function() {
-    chart.aspects.x[0].params.interval = 10;
+    (chart.aspects.x[0].params as HistogramParams).interval = 10;
 
     initXAxis(chart, table);
-    expect(chart)
-      .to.have.property('xAxisLabel', 'label')
-      .and.have.property('xAxisFormat', chart.aspects.x[0].format)
-      .and.have.property('ordered');
+    expect(chart).toHaveProperty('xAxisLabel', 'label');
+    expect(chart).toHaveProperty('xAxisFormat', chart.aspects.x[0].format);
+    expect(chart).toHaveProperty('ordered');
   });
 
   describe('xAxisOrderedValues', function() {
     it('sets the xAxisOrderedValues property', function() {
       initXAxis(chart, table);
-      expect(chart).to.have.property('xAxisOrderedValues');
+      expect(chart).toHaveProperty('xAxisOrderedValues');
     });
 
     it('returns a list of values, preserving the table order', function() {
       initXAxis(chart, table);
-      expect(chart.xAxisOrderedValues).to.eql(['hello', 'world', 'foo', 'bar', 'baz']);
+      expect(chart.xAxisOrderedValues).toEqual(['hello', 'world', 'foo', 'bar', 'baz']);
     });
 
     it('only returns unique values', function() {
       table = {
-        columns: [{ id: '0' }],
+        columns: [{ id: '0' } as Column],
         rows: [
           { '0': 'hello' },
           { '0': 'world' },
@@ -88,45 +94,46 @@ describe('initXAxis', function() {
         ],
       };
       initXAxis(chart, table);
-      expect(chart.xAxisOrderedValues).to.eql(['hello', 'world', 'foo', 'bar', 'baz']);
+      expect(chart.xAxisOrderedValues).toEqual(['hello', 'world', 'foo', 'bar', 'baz']);
     });
 
     it('returns the defaultValue if using fake x aspect', function() {
       chart = {
         aspects: {
           x: [makeFakeXAspect()],
-        },
-      };
+        } as Aspects,
+      } as Chart;
       initXAxis(chart, table);
-      expect(chart.xAxisOrderedValues).to.eql(['_all']);
+      expect(chart.xAxisOrderedValues).toEqual(['_all']);
     });
   });
 
   it('reads the date interval param from the x agg', function() {
-    chart.aspects.x[0].params.interval = 'P1D';
-    chart.aspects.x[0].params.intervalESValue = 1;
-    chart.aspects.x[0].params.intervalESUnit = 'd';
-    chart.aspects.x[0].params.date = true;
+    const dateHistogramParams = chart.aspects.x[0].params as DateHistogramParams;
+    dateHistogramParams.interval = 'P1D';
+    dateHistogramParams.intervalESValue = 1;
+    dateHistogramParams.intervalESUnit = 'd';
+    dateHistogramParams.date = true;
     initXAxis(chart, table);
-    expect(chart)
-      .to.have.property('xAxisLabel', 'label')
-      .and.have.property('xAxisFormat', chart.aspects.x[0].format)
-      .and.have.property('ordered');
+    expect(chart).toHaveProperty('xAxisLabel', 'label');
+    expect(chart).toHaveProperty('xAxisFormat', chart.aspects.x[0].format);
+    expect(chart).toHaveProperty('ordered');
 
-    expect(moment.isDuration(chart.ordered.interval)).to.be(true);
-    expect(chart.ordered.interval.toISOString()).to.eql('P1D');
-    expect(chart.ordered.intervalESValue).to.be(1);
-    expect(chart.ordered.intervalESUnit).to.be('d');
+    expect(chart.ordered).toEqual(expect.any(Object));
+    const { intervalESUnit, intervalESValue, interval } = chart.ordered as DateHistogramOrdered;
+    expect(moment.isDuration(interval)).toBe(true);
+    expect(interval.toISOString()).toEqual('P1D');
+    expect(intervalESValue).toBe(1);
+    expect(intervalESUnit).toBe('d');
   });
 
   it('reads the numeric interval param from the x agg', function() {
-    chart.aspects.x[0].params.interval = 0.5;
+    (chart.aspects.x[0].params as HistogramParams).interval = 0.5;
     initXAxis(chart, table);
-    expect(chart)
-      .to.have.property('xAxisLabel', 'label')
-      .and.have.property('xAxisFormat', chart.aspects.x[0].format)
-      .and.have.property('ordered');
+    expect(chart).toHaveProperty('xAxisLabel', 'label');
+    expect(chart).toHaveProperty('xAxisFormat', chart.aspects.x[0].format);
+    expect(chart).toHaveProperty('ordered');
 
-    expect(chart.ordered.interval).to.eql(0.5);
+    expect((chart.ordered as HistogramOrdered).interval).toEqual(0.5);
   });
 });
diff --git a/src/legacy/ui/public/agg_response/point_series/_init_x_axis.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.ts
similarity index 73%
rename from src/legacy/ui/public/agg_response/point_series/_init_x_axis.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.ts
index 4a81486783b08..9d16c4857be00 100644
--- a/src/legacy/ui/public/agg_response/point_series/_init_x_axis.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.ts
@@ -19,27 +19,31 @@
 
 import { uniq } from 'lodash';
 import moment from 'moment';
+import { Chart } from './point_series';
+import { Table } from '../../types';
 
-export function initXAxis(chart, table) {
+export function initXAxis(chart: Chart, table: Table) {
   const { format, title, params, accessor } = chart.aspects.x[0];
 
   chart.xAxisOrderedValues =
-    accessor === -1 ? [params.defaultValue] : uniq(table.rows.map(r => r[accessor]));
+    accessor === -1 && 'defaultValue' in params
+      ? [params.defaultValue]
+      : uniq(table.rows.map(r => r[accessor]));
   chart.xAxisFormat = format;
   chart.xAxisLabel = title;
 
-  const { interval, date } = params;
-  if (interval) {
-    if (date) {
+  if ('interval' in params) {
+    const { interval } = params;
+    if ('date' in params) {
       const { intervalESUnit, intervalESValue } = params;
       chart.ordered = {
         interval: moment.duration(interval),
-        intervalESUnit: intervalESUnit,
-        intervalESValue: intervalESValue,
+        intervalESUnit,
+        intervalESValue,
       };
     } else {
       chart.ordered = {
-        interval,
+        interval: params.interval,
       };
     }
   }
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_init_y_axis.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts
similarity index 81%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/_init_y_axis.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts
index 78cd5334e6c86..df84d69c9f849 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_init_y_axis.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts
@@ -18,8 +18,8 @@
  */
 
 import _ from 'lodash';
-import expect from '@kbn/expect';
-import { initYAxis } from '../_init_y_axis';
+import { initYAxis } from './_init_y_axis';
+import { Chart } from './point_series';
 
 describe('initYAxis', function() {
   const baseChart = {
@@ -34,7 +34,7 @@ describe('initYAxis', function() {
         },
       ],
     },
-  };
+  } as Chart;
 
   describe('with a single y aspect', function() {
     const singleYBaseChart = _.cloneDeep(baseChart);
@@ -43,13 +43,13 @@ describe('initYAxis', function() {
     it('sets the yAxisFormatter the the field formats convert fn', function() {
       const chart = _.cloneDeep(singleYBaseChart);
       initYAxis(chart);
-      expect(chart).to.have.property('yAxisFormat');
+      expect(chart).toHaveProperty('yAxisFormat');
     });
 
     it('sets the yAxisLabel', function() {
       const chart = _.cloneDeep(singleYBaseChart);
       initYAxis(chart);
-      expect(chart).to.have.property('yAxisLabel', 'y1');
+      expect(chart).toHaveProperty('yAxisLabel', 'y1');
     });
   });
 
@@ -58,16 +58,15 @@ describe('initYAxis', function() {
       const chart = _.cloneDeep(baseChart);
       initYAxis(chart);
 
-      expect(chart).to.have.property('yAxisFormat');
-      expect(chart.yAxisFormat)
-        .to.be(chart.aspects.y[0].format)
-        .and.not.be(chart.aspects.y[1].format);
+      expect(chart).toHaveProperty('yAxisFormat');
+      expect(chart.yAxisFormat).toBe(chart.aspects.y[0].format);
+      expect(chart.yAxisFormat).not.toBe(chart.aspects.y[1].format);
     });
 
     it('does not set the yAxisLabel, it does not make sense to put multiple labels on the same axis', function() {
       const chart = _.cloneDeep(baseChart);
       initYAxis(chart);
-      expect(chart).to.have.property('yAxisLabel', '');
+      expect(chart).toHaveProperty('yAxisLabel', '');
     });
   });
 });
diff --git a/src/legacy/ui/public/agg_response/point_series/_init_y_axis.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.ts
similarity index 82%
rename from src/legacy/ui/public/agg_response/point_series/_init_y_axis.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.ts
index 42f5e79a63172..43ba0557949ac 100644
--- a/src/legacy/ui/public/agg_response/point_series/_init_y_axis.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.ts
@@ -17,7 +17,9 @@
  * under the License.
  */
 
-export function initYAxis(chart) {
+import { Chart } from './point_series';
+
+export function initYAxis(chart: Chart) {
   const y = chart.aspects.y;
 
   if (Array.isArray(y)) {
@@ -28,12 +30,7 @@ export function initYAxis(chart) {
 
   const z = chart.aspects.series;
   if (z) {
-    if (Array.isArray(z)) {
-      chart.zAxisFormat = z[0].format;
-      chart.zAxisLabel = '';
-    } else {
-      chart.zAxisFormat = z.format;
-      chart.zAxisLabel = z.title;
-    }
+    chart.zAxisFormat = z[0].format;
+    chart.zAxisLabel = '';
   }
 }
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_ordered_date_axis.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts
similarity index 76%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/_ordered_date_axis.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts
index 2e08be16278d5..25e466f21c3e7 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_ordered_date_axis.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts
@@ -19,8 +19,8 @@
 
 import moment from 'moment';
 import _ from 'lodash';
-import expect from '@kbn/expect';
-import { orderedDateAxis } from '../_ordered_date_axis';
+import { orderedDateAxis } from './_ordered_date_axis';
+import { DateHistogramParams, OrderedChart } from './point_series';
 
 describe('orderedDateAxis', function() {
   const baseArgs = {
@@ -46,7 +46,7 @@ describe('orderedDateAxis', function() {
           },
         ],
       },
-    },
+    } as OrderedChart,
   };
 
   describe('ordered object', function() {
@@ -54,24 +54,24 @@ describe('orderedDateAxis', function() {
       const args = _.cloneDeep(baseArgs);
       orderedDateAxis(args.chart);
 
-      expect(args.chart).to.have.property('ordered');
+      expect(args.chart).toHaveProperty('ordered');
 
-      expect(args.chart.ordered).to.have.property('date', true);
+      expect(args.chart.ordered).toHaveProperty('date', true);
     });
 
     it('sets the min/max when the buckets are bounded', function() {
       const args = _.cloneDeep(baseArgs);
       orderedDateAxis(args.chart);
-      expect(args.chart.ordered).to.have.property('min');
-      expect(args.chart.ordered).to.have.property('max');
+      expect(args.chart.ordered).toHaveProperty('min');
+      expect(args.chart.ordered).toHaveProperty('max');
     });
 
     it('does not set the min/max when the buckets are unbounded', function() {
       const args = _.cloneDeep(baseArgs);
-      args.chart.aspects.x[0].params.bounds = null;
+      (args.chart.aspects.x[0].params as DateHistogramParams).bounds = undefined;
       orderedDateAxis(args.chart);
-      expect(args.chart.ordered).to.not.have.property('min');
-      expect(args.chart.ordered).to.not.have.property('max');
+      expect(args.chart.ordered).not.toHaveProperty('min');
+      expect(args.chart.ordered).not.toHaveProperty('max');
     });
   });
 });
diff --git a/src/legacy/ui/public/agg_response/point_series/_ordered_date_axis.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts
similarity index 72%
rename from src/legacy/ui/public/agg_response/point_series/_ordered_date_axis.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts
index a1dd50dc6c71b..193b10a563563 100644
--- a/src/legacy/ui/public/agg_response/point_series/_ordered_date_axis.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts
@@ -17,17 +17,17 @@
  * under the License.
  */
 
-// import moment from 'moment';
+import { OrderedChart } from './point_series';
 
-export function orderedDateAxis(chart) {
+export function orderedDateAxis(chart: OrderedChart) {
   const x = chart.aspects.x[0];
-  const { bounds } = x.params;
+  const bounds = 'bounds' in x.params ? x.params.bounds : undefined;
 
   chart.ordered.date = true;
 
   if (bounds) {
-    chart.ordered.min = isNaN(bounds.min) ? Date.parse(bounds.min) : bounds.min;
-    chart.ordered.max = isNaN(bounds.max) ? Date.parse(bounds.max) : bounds.max;
+    chart.ordered.min = typeof bounds.min === 'string' ? Date.parse(bounds.min) : bounds.min;
+    chart.ordered.max = typeof bounds.max === 'string' ? Date.parse(bounds.max) : bounds.max;
   } else {
     chart.ordered.endzones = false;
   }
diff --git a/src/legacy/ui/public/agg_response/index.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/index.ts
similarity index 69%
rename from src/legacy/ui/public/agg_response/index.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/index.ts
index 982c1c25a8101..9bfba4de966be 100644
--- a/src/legacy/ui/public/agg_response/index.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/index.ts
@@ -17,12 +17,4 @@
  * under the License.
  */
 
-import { buildHierarchicalData } from './hierarchical/build_hierarchical_data';
-import { buildPointSeriesData } from './point_series/point_series';
-import { search } from '../../../../plugins/data/public';
-
-export const aggResponseIndex = {
-  hierarchical: buildHierarchicalData,
-  pointSeries: buildPointSeriesData,
-  tabify: search.tabifyAggResponse,
-};
+export { buildPointSeriesData } from './point_series';
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_main.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts
similarity index 62%
rename from src/legacy/ui/public/agg_response/point_series/__tests__/_main.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts
index a4c23cb537488..3725bf06660e2 100644
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_main.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts
@@ -18,17 +18,25 @@
  */
 
 import _ from 'lodash';
-import expect from '@kbn/expect';
-import { buildPointSeriesData } from '../point_series';
+import { buildPointSeriesData, Dimensions } from './point_series';
+import { Table, Column } from '../../types';
+import { setFormatService } from '../../../services';
+import { Serie } from './_add_to_siri';
 
 describe('pointSeriesChartDataFromTable', function() {
-  this.slow(1000);
+  beforeAll(() => {
+    setFormatService({
+      deserialize: () => ({
+        convert: jest.fn(v => v),
+      }),
+    } as any);
+  });
 
   it('handles a table with just a count', function() {
     const table = {
-      columns: [{ id: '0' }],
+      columns: [{ id: '0' } as Column],
       rows: [{ '0': 100 }],
-    };
+    } as Table;
     const chartData = buildPointSeriesData(table, {
       y: [
         {
@@ -36,16 +44,15 @@ describe('pointSeriesChartDataFromTable', function() {
           params: {},
         },
       ],
-    });
+    } as Dimensions);
 
-    expect(chartData).to.be.an('object');
-    expect(chartData.series).to.be.an('array');
-    expect(chartData.series).to.have.length(1);
+    expect(chartData).toEqual(expect.any(Object));
+    expect(chartData.series).toEqual(expect.any(Array));
+    expect(chartData.series).toHaveLength(1);
     const series = chartData.series[0];
-    expect(series.values).to.have.length(1);
-    expect(series.values[0])
-      .to.have.property('x', '_all')
-      .and.have.property('y', 100);
+    expect(series.values).toHaveLength(1);
+    expect(series.values[0]).toHaveProperty('x', '_all');
+    expect(series.values[0]).toHaveProperty('y', 100);
   });
 
   it('handles a table with x and y column', function() {
@@ -59,21 +66,21 @@ describe('pointSeriesChartDataFromTable', function() {
         { '0': 2, '1': 200 },
         { '0': 3, '1': 200 },
       ],
-    };
+    } as Table;
 
     const dimensions = {
-      x: [{ accessor: 0, params: {} }],
+      x: { accessor: 0, params: {} },
       y: [{ accessor: 1, params: {} }],
-    };
+    } as Dimensions;
 
     const chartData = buildPointSeriesData(table, dimensions);
 
-    expect(chartData).to.be.an('object');
-    expect(chartData.series).to.be.an('array');
-    expect(chartData.series).to.have.length(1);
+    expect(chartData).toEqual(expect.any(Object));
+    expect(chartData.series).toEqual(expect.any(Array));
+    expect(chartData.series).toHaveLength(1);
     const series = chartData.series[0];
-    expect(series).to.have.property('label', 'Count');
-    expect(series.values).to.have.length(3);
+    expect(series).toHaveProperty('label', 'Count');
+    expect(series.values).toHaveLength(3);
   });
 
   it('handles a table with an x and two y aspects', function() {
@@ -84,23 +91,23 @@ describe('pointSeriesChartDataFromTable', function() {
         { '0': 2, '1': 200, '2': 300 },
         { '0': 3, '1': 200, '2': 300 },
       ],
-    };
+    } as Table;
 
     const dimensions = {
-      x: [{ accessor: 0, params: {} }],
+      x: { accessor: 0, params: {} },
       y: [
         { accessor: 1, params: {} },
         { accessor: 2, params: {} },
       ],
-    };
+    } as Dimensions;
 
     const chartData = buildPointSeriesData(table, dimensions);
-    expect(chartData).to.be.an('object');
-    expect(chartData.series).to.be.an('array');
-    expect(chartData.series).to.have.length(2);
-    chartData.series.forEach(function(siri, i) {
-      expect(siri).to.have.property('label', `Count-${i}`);
-      expect(siri.values).to.have.length(3);
+    expect(chartData).toEqual(expect.any(Object));
+    expect(chartData.series).toEqual(expect.any(Array));
+    expect(chartData.series).toHaveLength(2);
+    chartData.series.forEach(function(siri: Serie, i: number) {
+      expect(siri).toHaveProperty('label', `Count-${i}`);
+      expect(siri.values).toHaveLength(3);
     });
   });
 
@@ -121,21 +128,21 @@ describe('pointSeriesChartDataFromTable', function() {
     };
 
     const dimensions = {
-      x: [{ accessor: 0, params: {} }],
+      x: { accessor: 0, params: {} },
       series: [{ accessor: 1, params: {} }],
       y: [
         { accessor: 2, params: {} },
         { accessor: 3, params: {} },
       ],
-    };
+    } as Dimensions;
 
     const chartData = buildPointSeriesData(table, dimensions);
-    expect(chartData).to.be.an('object');
-    expect(chartData.series).to.be.an('array');
+    expect(chartData).toEqual(expect.any(Object));
+    expect(chartData.series).toEqual(expect.any(Array));
     // one series for each extension, and then one for each metric inside
-    expect(chartData.series).to.have.length(4);
-    chartData.series.forEach(function(siri) {
-      expect(siri.values).to.have.length(2);
+    expect(chartData.series).toHaveLength(4);
+    chartData.series.forEach(function(siri: Serie) {
+      expect(siri.values).toHaveLength(2);
     });
   });
 });
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts
new file mode 100644
index 0000000000000..a1681e0d71bd3
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts
@@ -0,0 +1,118 @@
+/*
+ * 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 { Duration } from 'moment';
+import { getSeries } from './_get_series';
+import { getAspects } from './_get_aspects';
+import { initYAxis } from './_init_y_axis';
+import { initXAxis } from './_init_x_axis';
+import { orderedDateAxis } from './_ordered_date_axis';
+import { Serie } from './_add_to_siri';
+import { Column, Table } from '../../types';
+
+export interface DateHistogramParams {
+  date: boolean;
+  interval: string;
+  intervalESValue: number;
+  intervalESUnit: string;
+  format: string;
+  bounds?: {
+    min: string | number;
+    max: string | number;
+  };
+}
+export interface HistogramParams {
+  interval: number;
+}
+export interface FakeParams {
+  defaultValue: string;
+}
+export interface Dimension {
+  accessor: number;
+  format: {
+    id?: string;
+    params?: { pattern?: string; [key: string]: any };
+  };
+  params: DateHistogramParams | HistogramParams | FakeParams | {};
+}
+
+export interface Dimensions {
+  x: Dimension | null;
+  y: Dimension[];
+  z?: Dimension[];
+  series?: Dimension | Dimension[];
+}
+export interface Aspect {
+  accessor: Column['id'];
+  column?: Dimension['accessor'];
+  title: Column['name'];
+  format: Dimension['format'];
+  params: Dimension['params'];
+}
+export type Aspects = { x: Aspect[]; y: Aspect[] } & { [key in keyof Dimensions]?: Aspect[] };
+
+export interface DateHistogramOrdered {
+  interval: Duration;
+  intervalESUnit: DateHistogramParams['intervalESUnit'];
+  intervalESValue: DateHistogramParams['intervalESValue'];
+}
+export interface HistogramOrdered {
+  interval: HistogramParams['interval'];
+}
+
+type Ordered = (DateHistogramOrdered | HistogramOrdered) & {
+  date?: boolean;
+  min?: number;
+  max?: number;
+  endzones?: boolean;
+};
+
+export interface Chart {
+  aspects: Aspects;
+  series: Serie[];
+  xAxisOrderedValues?: Array<string | number | object>;
+  xAxisFormat?: Dimension['format'];
+  xAxisLabel?: Column['name'];
+  yAxisFormat?: Dimension['format'];
+  yAxisLabel?: Column['name'];
+  zAxisFormat?: Dimension['format'];
+  zAxisLabel?: Column['name'];
+  ordered?: Ordered;
+}
+
+export type OrderedChart = Chart & { ordered: Ordered };
+
+export const buildPointSeriesData = (table: Table, dimensions: Dimensions) => {
+  const chart = {
+    aspects: getAspects(table, dimensions),
+  } as Chart;
+
+  initXAxis(chart, table);
+  initYAxis(chart);
+
+  if ('date' in chart.aspects.x[0].params) {
+    // initXAxis will turn `chart` into an `OrderedChart if it is a date axis`
+    orderedDateAxis(chart as OrderedChart);
+  }
+
+  chart.series = getSeries(table, chart);
+
+  delete chart.aspects;
+  return chart;
+};
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.js
index 9ba86c5181a4c..b5f80303b1d74 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.js
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-import { buildHierarchicalData, buildPointSeriesData } from '../legacy_imports';
 import { getFormatService } from '../services';
+import { buildHierarchicalData, buildPointSeriesData } from './helpers';
 
 function tableResponseHandler(table, dimensions) {
   const converted = { tables: [] };
@@ -72,7 +72,7 @@ function tableResponseHandler(table, dimensions) {
 function convertTableGroup(tableGroup, convertTable) {
   const tables = tableGroup.tables;
 
-  if (!tables.length) return;
+  if (!tables || !tables.length) return;
 
   const firstChild = tables[0];
   if (firstChild.columns) {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.test.ts b/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.test.ts
new file mode 100644
index 0000000000000..4a8bebc493235
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/response_handler.test.ts
@@ -0,0 +1,130 @@
+/*
+ * 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 { setFormatService } from '../services';
+
+jest.mock('./helpers', () => ({
+  buildHierarchicalData: jest.fn(() => ({})),
+  buildPointSeriesData: jest.fn(() => ({})),
+}));
+
+// @ts-ignore
+import { vislibSeriesResponseHandler, vislibSlicesResponseHandler } from './response_handler';
+import { buildHierarchicalData, buildPointSeriesData } from './helpers';
+import { Table } from './types';
+
+describe('response_handler', () => {
+  describe('vislibSlicesResponseHandler', () => {
+    test('should not call buildHierarchicalData when no columns', () => {
+      vislibSlicesResponseHandler({ rows: [] }, {});
+      expect(buildHierarchicalData).not.toHaveBeenCalled();
+    });
+
+    test('should call buildHierarchicalData', () => {
+      const response = {
+        rows: [{ 'col-0-1': 1 }],
+        columns: [{ id: 'col-0-1', name: 'Count' }],
+      };
+      const dimensions = { metric: { accessor: 0 } };
+      vislibSlicesResponseHandler(response, dimensions);
+
+      expect(buildHierarchicalData).toHaveBeenCalledWith(
+        { columns: [...response.columns], rows: [...response.rows] },
+        dimensions
+      );
+    });
+  });
+
+  describe('vislibSeriesResponseHandler', () => {
+    let resp: Table;
+    let expected: any;
+
+    beforeAll(() => {
+      setFormatService({
+        deserialize: () => ({
+          convert: jest.fn(v => v),
+        }),
+      } as any);
+    });
+
+    beforeAll(() => {
+      resp = {
+        rows: [
+          { 'col-0-3': 158599872, 'col-1-1': 1 },
+          { 'col-0-3': 158599893, 'col-1-1': 2 },
+          { 'col-0-3': 158599908, 'col-1-1': 1 },
+        ],
+        columns: [
+          { id: 'col-0-3', name: 'timestamp per 30 seconds' },
+          { id: 'col-1-1', name: 'Count' },
+        ],
+      } as Table;
+
+      const colId = resp.columns[0].id;
+      expected = [
+        { label: `${resp.rows[0][colId]}: ${resp.columns[0].name}` },
+        { label: `${resp.rows[1][colId]}: ${resp.columns[0].name}` },
+        { label: `${resp.rows[2][colId]}: ${resp.columns[0].name}` },
+      ];
+    });
+
+    test('should not call buildPointSeriesData when no columns', () => {
+      vislibSeriesResponseHandler({ rows: [] }, {});
+      expect(buildPointSeriesData).not.toHaveBeenCalled();
+    });
+
+    test('should call buildPointSeriesData', () => {
+      const response = {
+        rows: [{ 'col-0-1': 1 }],
+        columns: [{ id: 'col-0-1', name: 'Count' }],
+      };
+      const dimensions = { x: null, y: { accessor: 0 } };
+      vislibSeriesResponseHandler(response, dimensions);
+
+      expect(buildPointSeriesData).toHaveBeenCalledWith(
+        { columns: [...response.columns], rows: [...response.rows] },
+        dimensions
+      );
+    });
+
+    test('should split columns', () => {
+      const dimensions = {
+        x: null,
+        y: [{ accessor: 1 }],
+        splitColumn: [{ accessor: 0 }],
+      };
+
+      const convertedResp = vislibSlicesResponseHandler(resp, dimensions);
+      expect(convertedResp.columns).toHaveLength(resp.rows.length);
+      expect(convertedResp.columns).toEqual(expected);
+    });
+
+    test('should split rows', () => {
+      const dimensions = {
+        x: null,
+        y: [{ accessor: 1 }],
+        splitRow: [{ accessor: 0 }],
+      };
+
+      const convertedResp = vislibSlicesResponseHandler(resp, dimensions);
+      expect(convertedResp.rows).toHaveLength(resp.rows.length);
+      expect(convertedResp.rows).toEqual(expected);
+    });
+  });
+});
diff --git a/src/legacy/ui/public/agg_response/point_series/_add_to_siri.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/types.ts
similarity index 67%
rename from src/legacy/ui/public/agg_response/point_series/_add_to_siri.js
rename to src/legacy/core_plugins/vis_type_vislib/public/vislib/types.ts
index 9a0fcbc7b267c..ad59603663b84 100644
--- a/src/legacy/ui/public/agg_response/point_series/_add_to_siri.js
+++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/types.ts
@@ -17,22 +17,26 @@
  * under the License.
  */
 
-export function addToSiri(series, point, id, yLabel, yFormat, zFormat, zLabel) {
-  id = id == null ? '' : id + '';
+export interface Column {
+  // -1 value can be in a fake X aspect
+  id: string | -1;
+  name: string;
+}
 
-  if (series.has(id)) {
-    series.get(id).values.push(point);
-    return;
-  }
+export interface Row {
+  [key: string]: number | string | object;
+}
 
-  series.set(id, {
-    id: id.split('-').pop(),
-    rawId: id,
-    label: yLabel == null ? id : yLabel,
-    count: 0,
-    values: [point],
-    format: yFormat,
-    zLabel,
-    zFormat,
-  });
+export interface TableParent {
+  table: Table;
+  tables?: Table[];
+  column: number;
+  row: number;
+  key: number;
+  name: string;
+}
+export interface Table {
+  columns: Column[];
+  rows: Row[];
+  $parent?: TableParent;
 }
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_add_to_siri.js b/src/legacy/ui/public/agg_response/point_series/__tests__/_add_to_siri.js
deleted file mode 100644
index 43a10ebbfb12e..0000000000000
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_add_to_siri.js
+++ /dev/null
@@ -1,82 +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 expect from '@kbn/expect';
-import { addToSiri } from '../_add_to_siri';
-
-describe('addToSiri', function() {
-  it('creates a new series the first time it sees an id', function() {
-    const series = new Map();
-    const point = {};
-    const id = 'id';
-    addToSiri(series, point, id, id, { id: id });
-
-    expect(series.has(id)).to.be(true);
-    expect(series.get(id)).to.be.an('object');
-    expect(series.get(id).label).to.be(id);
-    expect(series.get(id).values).to.have.length(1);
-    expect(series.get(id).values[0]).to.be(point);
-  });
-
-  it('adds points to existing series if id has been seen', function() {
-    const series = new Map();
-    const id = 'id';
-
-    const point = {};
-    addToSiri(series, point, id, id, { id: id });
-
-    const point2 = {};
-    addToSiri(series, point2, id, id, { id: id });
-
-    expect(series.has(id)).to.be(true);
-    expect(series.get(id)).to.be.an('object');
-    expect(series.get(id).label).to.be(id);
-    expect(series.get(id).values).to.have.length(2);
-    expect(series.get(id).values[0]).to.be(point);
-    expect(series.get(id).values[1]).to.be(point2);
-  });
-
-  it('allows overriding the series label', function() {
-    const series = new Map();
-    const id = 'id';
-    const label = 'label';
-    const point = {};
-    addToSiri(series, point, id, label, { id: id });
-
-    expect(series.has(id)).to.be(true);
-    expect(series.get(id)).to.be.an('object');
-    expect(series.get(id).label).to.be(label);
-    expect(series.get(id).values).to.have.length(1);
-    expect(series.get(id).values[0]).to.be(point);
-  });
-
-  it('correctly sets id and rawId', function() {
-    const series = new Map();
-    const id = 'id-id2';
-
-    const point = {};
-    addToSiri(series, point, id);
-
-    expect(series.has(id)).to.be(true);
-    expect(series.get(id)).to.be.an('object');
-    expect(series.get(id).label).to.be(id);
-    expect(series.get(id).rawId).to.be(id);
-    expect(series.get(id).id).to.be('id2');
-  });
-});
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_get_point.js b/src/legacy/ui/public/agg_response/point_series/__tests__/_get_point.js
deleted file mode 100644
index 0eb2c608d6d6c..0000000000000
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_get_point.js
+++ /dev/null
@@ -1,97 +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 expect from '@kbn/expect';
-import { getPoint } from '../_get_point';
-
-describe('getPoint', function() {
-  const table = {
-    columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-    rows: [
-      { '0': 1, '1': 2, '2': 3 },
-      { '0': 4, '1': 'NaN', '2': 6 },
-    ],
-  };
-
-  describe('Without series aspect', function() {
-    let seriesAspect;
-    let xAspect;
-    let yAspect;
-    let yScale;
-
-    beforeEach(function() {
-      seriesAspect = null;
-      xAspect = { accessor: 0 };
-      yAspect = { accessor: 1, title: 'Y' };
-      yScale = 5;
-    });
-
-    it('properly unwraps and scales values', function() {
-      const row = table.rows[0];
-      const zAspect = { accessor: 2 };
-      const point = getPoint(table, xAspect, seriesAspect, yScale, row, 0, yAspect, zAspect);
-
-      expect(point)
-        .to.have.property('x', 1)
-        .and.have.property('y', 10)
-        .and.have.property('z', 3)
-        .and.have.property('series', yAspect.title);
-    });
-
-    it('ignores points with a y value of NaN', function() {
-      const row = table.rows[1];
-      const point = getPoint(table, xAspect, seriesAspect, yScale, row, 1, yAspect);
-      expect(point).to.be(void 0);
-    });
-  });
-
-  describe('With series aspect', function() {
-    let row;
-    let xAspect;
-    let yAspect;
-    let yScale;
-
-    beforeEach(function() {
-      row = table.rows[0];
-      xAspect = { accessor: 0 };
-      yAspect = { accessor: 2 };
-      yScale = null;
-    });
-
-    it('properly unwraps and scales values', function() {
-      const seriesAspect = [{ accessor: 1 }];
-      const point = getPoint(table, xAspect, seriesAspect, yScale, row, 0, yAspect);
-
-      expect(point)
-        .to.have.property('x', 1)
-        .and.have.property('series', '2')
-        .and.have.property('y', 3);
-    });
-
-    it('properly formats series values', function() {
-      const seriesAspect = [{ accessor: 1, format: { id: 'number', params: { pattern: '$' } } }];
-      const point = getPoint(table, xAspect, seriesAspect, yScale, row, 0, yAspect);
-
-      expect(point)
-        .to.have.property('x', 1)
-        .and.have.property('series', '$2')
-        .and.have.property('y', 3);
-    });
-  });
-});
diff --git a/src/legacy/ui/public/agg_response/point_series/__tests__/_get_series.js b/src/legacy/ui/public/agg_response/point_series/__tests__/_get_series.js
deleted file mode 100644
index 1727994976383..0000000000000
--- a/src/legacy/ui/public/agg_response/point_series/__tests__/_get_series.js
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import _ from 'lodash';
-import expect from '@kbn/expect';
-import { getSeries } from '../_get_series';
-
-describe('getSeries', function() {
-  it('produces a single series with points for each row', function() {
-    const table = {
-      columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-      rows: [
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-      ],
-    };
-
-    const chart = {
-      aspects: {
-        x: [{ accessor: 0 }],
-        y: [{ accessor: 1, title: 'y' }],
-        z: { accessor: 2 },
-      },
-    };
-
-    const series = getSeries(table, chart);
-
-    expect(series)
-      .to.be.an('array')
-      .and.to.have.length(1);
-
-    const siri = series[0];
-    expect(siri)
-      .to.be.an('object')
-      .and.have.property('label', chart.aspects.y.title)
-      .and.have.property('values');
-
-    expect(siri.values)
-      .to.be.an('array')
-      .and.have.length(5);
-
-    siri.values.forEach(function(point) {
-      expect(point)
-        .to.have.property('x', 1)
-        .and.property('y', 2)
-        .and.property('z', 3);
-    });
-  });
-
-  it('adds the seriesId to each point', function() {
-    const table = {
-      columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-      rows: [
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-      ],
-    };
-
-    const chart = {
-      aspects: {
-        x: [{ accessor: 0 }],
-        y: [
-          { accessor: 1, title: '0' },
-          { accessor: 2, title: '1' },
-        ],
-      },
-    };
-
-    const series = getSeries(table, chart);
-
-    series[0].values.forEach(function(point) {
-      expect(point).to.have.property('seriesId', 1);
-    });
-
-    series[1].values.forEach(function(point) {
-      expect(point).to.have.property('seriesId', 2);
-    });
-  });
-
-  it('produces multiple series if there are multiple y aspects', function() {
-    const table = {
-      columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-      rows: [
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-      ],
-    };
-
-    const chart = {
-      aspects: {
-        x: [{ accessor: 0 }],
-        y: [
-          { accessor: 1, title: '0' },
-          { accessor: 2, title: '1' },
-        ],
-      },
-    };
-
-    const series = getSeries(table, chart);
-
-    expect(series)
-      .to.be.an('array')
-      .and.to.have.length(2);
-
-    series.forEach(function(siri, i) {
-      expect(siri)
-        .to.be.an('object')
-        .and.have.property('label', '' + i)
-        .and.have.property('values');
-
-      expect(siri.values)
-        .to.be.an('array')
-        .and.have.length(5);
-
-      siri.values.forEach(function(point) {
-        expect(point)
-          .to.have.property('x', 1)
-          .and.property('y', i + 2);
-      });
-    });
-  });
-
-  it('produces multiple series if there is a series aspect', function() {
-    const table = {
-      columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-      rows: [
-        { '0': 0, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 0, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 0, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-      ],
-    };
-
-    const chart = {
-      aspects: {
-        x: [{ accessor: -1 }],
-        series: [{ accessor: 0, fieldFormatter: _.identity }],
-        y: [{ accessor: 1, title: '0' }],
-      },
-    };
-
-    const series = getSeries(table, chart);
-
-    expect(series)
-      .to.be.an('array')
-      .and.to.have.length(2);
-
-    series.forEach(function(siri, i) {
-      expect(siri)
-        .to.be.an('object')
-        .and.have.property('label', '' + i)
-        .and.have.property('values');
-
-      expect(siri.values)
-        .to.be.an('array')
-        .and.have.length(3);
-
-      siri.values.forEach(function(point) {
-        expect(point).to.have.property('y', 2);
-      });
-    });
-  });
-
-  it('produces multiple series if there is a series aspect and multiple y aspects', function() {
-    const table = {
-      columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-      rows: [
-        { '0': 0, '1': 3, '2': 4 },
-        { '0': 1, '1': 3, '2': 4 },
-        { '0': 0, '1': 3, '2': 4 },
-        { '0': 1, '1': 3, '2': 4 },
-        { '0': 0, '1': 3, '2': 4 },
-        { '0': 1, '1': 3, '2': 4 },
-      ],
-    };
-
-    const chart = {
-      aspects: {
-        x: [{ accessor: -1 }],
-        series: [{ accessor: 0, fieldFormatter: _.identity }],
-        y: [
-          { accessor: 1, title: '0' },
-          { accessor: 2, title: '1' },
-        ],
-      },
-    };
-
-    const series = getSeries(table, chart);
-
-    expect(series)
-      .to.be.an('array')
-      .and.to.have.length(4); // two series * two metrics
-
-    checkSiri(series[0], '0: 0', 3);
-    checkSiri(series[1], '0: 1', 4);
-    checkSiri(series[2], '1: 0', 3);
-    checkSiri(series[3], '1: 1', 4);
-
-    function checkSiri(siri, label, y) {
-      expect(siri)
-        .to.be.an('object')
-        .and.have.property('label', label)
-        .and.have.property('values');
-
-      expect(siri.values)
-        .to.be.an('array')
-        .and.have.length(3);
-
-      siri.values.forEach(function(point) {
-        expect(point).to.have.property('y', y);
-      });
-    }
-  });
-
-  it('produces a series list in the same order as its corresponding metric column', function() {
-    const table = {
-      columns: [{ id: '0' }, { id: '1' }, { id: '3' }],
-      rows: [
-        { '0': 0, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 0, '1': 2, '2': 3 },
-        { '0': 1, '1': 2, '2': 3 },
-        { '0': 0, '1': 2, '2': 3 },
-      ],
-    };
-
-    const chart = {
-      aspects: {
-        x: [{ accessor: -1 }],
-        series: [{ accessor: 0, fieldFormatter: _.identity }],
-        y: [
-          { accessor: 1, title: '0' },
-          { accessor: 2, title: '1' },
-        ],
-      },
-    };
-
-    const series = getSeries(table, chart);
-    expect(series[0]).to.have.property('label', '0: 0');
-    expect(series[1]).to.have.property('label', '0: 1');
-    expect(series[2]).to.have.property('label', '1: 0');
-    expect(series[3]).to.have.property('label', '1: 1');
-
-    // switch the order of the y columns
-    chart.aspects.y = chart.aspects.y.reverse();
-    chart.aspects.y.forEach(function(y, i) {
-      y.i = i;
-    });
-
-    const series2 = getSeries(table, chart);
-    expect(series2[0]).to.have.property('label', '0: 1');
-    expect(series2[1]).to.have.property('label', '0: 0');
-    expect(series2[2]).to.have.property('label', '1: 1');
-    expect(series2[3]).to.have.property('label', '1: 0');
-  });
-});
diff --git a/src/legacy/ui/public/agg_response/point_series/_get_series.js b/src/legacy/ui/public/agg_response/point_series/_get_series.js
deleted file mode 100644
index 73c1735191abc..0000000000000
--- a/src/legacy/ui/public/agg_response/point_series/_get_series.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import _ from 'lodash';
-import { getPoint } from './_get_point';
-import { addToSiri } from './_add_to_siri';
-
-export function getSeries(table, chart) {
-  const aspects = chart.aspects;
-  const xAspect = aspects.x[0];
-  const yAspect = aspects.y[0];
-  const zAspect = aspects.z && aspects.z.length ? aspects.z[0] : aspects.z;
-  const multiY = Array.isArray(aspects.y) && aspects.y.length > 1;
-  const yScale = chart.yScale;
-
-  const partGetPoint = _.partial(getPoint, table, xAspect, aspects.series, yScale);
-
-  let series = _(table.rows)
-    .transform(function(series, row, rowIndex) {
-      if (!multiY) {
-        const point = partGetPoint(row, rowIndex, yAspect, zAspect);
-        if (point) {
-          const id = `${point.series}-${yAspect.accessor}`;
-          point.seriesId = id;
-          addToSiri(
-            series,
-            point,
-            id,
-            point.series,
-            yAspect.format,
-            zAspect && zAspect.format,
-            zAspect && zAspect.title
-          );
-        }
-        return;
-      }
-
-      aspects.y.forEach(function(y) {
-        const point = partGetPoint(row, rowIndex, y, zAspect);
-        if (!point) return;
-
-        // use the point's y-axis as it's series by default,
-        // but augment that with series aspect if it's actually
-        // available
-        let seriesId = y.accessor;
-        let seriesLabel = y.title;
-
-        if (aspects.series) {
-          const prefix = point.series ? point.series + ': ' : '';
-          seriesId = prefix + seriesId;
-          seriesLabel = prefix + seriesLabel;
-        }
-
-        point.seriesId = seriesId;
-        addToSiri(
-          series,
-          point,
-          seriesId,
-          seriesLabel,
-          y.format,
-          zAspect && zAspect.format,
-          zAspect && zAspect.title
-        );
-      });
-    }, new Map())
-    .thru(series => [...series.values()])
-    .value();
-
-  if (multiY) {
-    series = _.sortBy(series, function(siri) {
-      const firstVal = siri.values[0];
-      let y;
-
-      if (firstVal) {
-        y = _.find(aspects.y, function(y) {
-          return y.accessor === firstVal.accessor;
-        });
-      }
-
-      return y ? y.i : series.length;
-    });
-  }
-  return series;
-}
diff --git a/src/legacy/ui/public/agg_response/point_series/point_series.js b/src/legacy/ui/public/agg_response/point_series/point_series.js
deleted file mode 100644
index 8489f7bc2ca45..0000000000000
--- a/src/legacy/ui/public/agg_response/point_series/point_series.js
+++ /dev/null
@@ -1,42 +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 { getSeries } from './_get_series';
-import { getAspects } from './_get_aspects';
-import { initYAxis } from './_init_y_axis';
-import { initXAxis } from './_init_x_axis';
-import { orderedDateAxis } from './_ordered_date_axis';
-
-export const buildPointSeriesData = (table, dimensions) => {
-  const chart = {
-    aspects: getAspects(table, dimensions),
-  };
-
-  initXAxis(chart, table);
-  initYAxis(chart);
-
-  if (chart.aspects.x[0].params.date) {
-    orderedDateAxis(chart);
-  }
-
-  chart.series = getSeries(table, chart);
-
-  delete chart.aspects;
-  return chart;
-};
diff --git a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js
index 905c88a6d18a0..532c49803e7b0 100644
--- a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js
+++ b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js
@@ -27,7 +27,6 @@ import 'uiExports/search';
 import 'uiExports/shareContextMenuExtensions';
 import _ from 'lodash';
 import 'ui/autoload/all';
-import 'ui/agg_response';
 import 'leaflet';
 import { npStart } from 'ui/new_platform';
 import { localApplicationService } from 'plugins/kibana/local_application_service';
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index d357e40c02934..705a4577cbd07 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -130,7 +130,6 @@
     "charts.colormaps.greysText": "グレー",
     "charts.colormaps.redsText": "赤",
     "charts.colormaps.yellowToRedText": "黄色から赤",
-    "common.ui.aggResponse.allDocsTitle": "すべてのドキュメント",
     "common.ui.errorAutoCreateIndex.breadcrumbs.errorText": "エラー",
     "common.ui.errorAutoCreateIndex.errorDescription": "Elasticsearch クラスターの {autoCreateIndexActionConfig} 設定が原因で、Kibana が保存されたオブジェクトを格納するインデックスを自動的に作成できないようです。Kibana は、保存されたオブジェクトインデックスが適切なマッピング/スキーマを使用し Kibana から Elasticsearch へのポーリングの回数を減らすための最適な手段であるため、この Elasticsearch の機能を使用します。",
     "common.ui.errorAutoCreateIndex.errorDisclaimer": "申し訳ございませんが、この問題が解決されるまで Kibana で何も保存することができません。",
@@ -3809,6 +3808,7 @@
     "visTypeVega.visualization.renderErrorTitle": "Vega エラー",
     "visTypeVega.visualization.unableToFindDefaultIndexErrorMessage": "デフォルトのインデックスが見つかりません",
     "visTypeVega.visualization.unableToRenderWithoutDataWarningMessage": "データなしにはレンダリングできません",
+    "visTypeVislib.aggResponse.allDocsTitle": "すべてのドキュメント",
     "visTypeVislib.area.areaDescription": "折れ線グラフの下の数量を強調します。",
     "visTypeVislib.area.areaTitle": "エリア",
     "visTypeVislib.area.countText": "カウント",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 839c89f3b1cae..50b807a4934ed 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -130,7 +130,6 @@
     "charts.colormaps.greysText": "灰色",
     "charts.colormaps.redsText": "红色",
     "charts.colormaps.yellowToRedText": "黄到红",
-    "common.ui.aggResponse.allDocsTitle": "所有文档",
     "common.ui.errorAutoCreateIndex.breadcrumbs.errorText": "错误",
     "common.ui.errorAutoCreateIndex.errorDescription": "似乎 Elasticsearch 集群的 {autoCreateIndexActionConfig} 设置使 Kibana 无法自动创建用于存储已保存对象的索引。Kibana 将使用此 Elasticsearch 功能,因为这是确保已保存对象索引使用正确映射/架构的最好方式,而且其允许 Kibana 较少地轮询 Elasticsearch。",
     "common.ui.errorAutoCreateIndex.errorDisclaimer": "但是,只有解决了此问题后,您才能在 Kibana 保存内容。",
@@ -3810,6 +3809,7 @@
     "visTypeVega.visualization.renderErrorTitle": "Vega 错误",
     "visTypeVega.visualization.unableToFindDefaultIndexErrorMessage": "找不到默认索引",
     "visTypeVega.visualization.unableToRenderWithoutDataWarningMessage": "没有数据时无法渲染",
+    "visTypeVislib.aggResponse.allDocsTitle": "所有文档",
     "visTypeVislib.area.areaDescription": "突出折线图下方的数量",
     "visTypeVislib.area.areaTitle": "面积图",
     "visTypeVislib.area.countText": "计数",

From b73fe279d6609162530619b4582f7f1da35a88c6 Mon Sep 17 00:00:00 2001
From: Jen Huang <its.jenetic@gmail.com>
Date: Thu, 9 Apr 2020 09:44:33 -0700
Subject: [PATCH 29/78] [EPM] Update UI copy to use `integration` (#63077)

* Update epm copy to say Integrations

* Update copy in create data source flow

* Update copy in data sources table

* Fix missed copies

* Remove unused translation keys (they were renamed & strings were changed)
---
 .../ingest_manager/layouts/default.tsx         |  4 ++--
 .../components/layout.tsx                      |  2 +-
 .../components/navigation.tsx                  |  2 +-
 .../create_datasource_page/index.tsx           |  2 +-
 .../step_select_package.tsx                    |  8 ++++----
 .../datasources/datasources_table.tsx          |  2 +-
 .../epm/components/package_list_grid.tsx       |  2 +-
 .../sections/epm/screens/detail/header.tsx     |  8 +++++++-
 .../sections/epm/screens/home/header.tsx       |  4 ++--
 .../sections/epm/screens/home/index.tsx        | 18 +++++++++---------
 .../translations/translations/ja-JP.json       |  5 -----
 .../translations/translations/zh-CN.json       |  5 -----
 12 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx
index 8ec2d2ec03b35..26f2c85a291a3 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx
@@ -55,8 +55,8 @@ export const DefaultLayout: React.FunctionComponent<Props> = ({ section, childre
                 disabled={!epm?.enabled}
               >
                 <FormattedMessage
-                  id="xpack.ingestManager.appNavigation.packagesLinkText"
-                  defaultMessage="Packages"
+                  id="xpack.ingestManager.appNavigation.epmLinkText"
+                  defaultMessage="Integrations"
                 />
               </EuiTab>
               <EuiTab isSelected={section === 'agent_config'} href={useLink(AGENT_CONFIG_PATH)}>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx
index 8bb7b2553c1b1..dd242f366e8c0 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx
@@ -88,7 +88,7 @@ export const CreateDatasourcePageLayout: React.FunctionComponent<{
                     <EuiDescriptionListTitle>
                       <FormattedMessage
                         id="xpack.ingestManager.createDatasource.packageNameLabel"
-                        defaultMessage="Package"
+                        defaultMessage="Integration"
                       />
                     </EuiDescriptionListTitle>
                     <EuiDescriptionListDescription>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx
index 099a7a83caa10..7dae981e65c30 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx
@@ -27,7 +27,7 @@ export const CreateDatasourceStepsNavigation: React.FunctionComponent<{
     from === 'config'
       ? {
           title: i18n.translate('xpack.ingestManager.createDatasource.stepSelectPackageLabel', {
-            defaultMessage: 'Select package',
+            defaultMessage: 'Select integration',
           }),
           isSelected: currentStep === 'selectPackage',
           isComplete:
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
index 7815ab9cd1d6e..461bb750ca6f5 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
@@ -221,7 +221,7 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
                     {from === 'config' ? (
                       <FormattedMessage
                         id="xpack.ingestManager.createDatasource.changePackageLinkText"
-                        defaultMessage="Change package"
+                        defaultMessage="Change integration"
                       />
                     ) : (
                       <FormattedMessage
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx
index cc7fc89ab8a80..496e1d3c0fd7b 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx
@@ -99,7 +99,7 @@ export const StepSelectPackage: React.FunctionComponent<{
         title={
           <FormattedMessage
             id="xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingPackagesTitle"
-            defaultMessage="Error loading packages"
+            defaultMessage="Error loading integrations"
           />
         }
         error={packagesError}
@@ -114,7 +114,7 @@ export const StepSelectPackage: React.FunctionComponent<{
           <h3>
             <FormattedMessage
               id="xpack.ingestManager.createDatasource.stepSelectPackage.selectPackageTitle"
-              defaultMessage="Select a package"
+              defaultMessage="Select integration"
             />
           </h3>
         </EuiTitle>
@@ -149,7 +149,7 @@ export const StepSelectPackage: React.FunctionComponent<{
             placeholder: i18n.translate(
               'xpack.ingestManager.createDatasource.stepSelectPackage.filterPackagesInputPlaceholder',
               {
-                defaultMessage: 'Search for packages',
+                defaultMessage: 'Search for integrations',
               }
             ),
           }}
@@ -179,7 +179,7 @@ export const StepSelectPackage: React.FunctionComponent<{
             title={
               <FormattedMessage
                 id="xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingSelectedPackageTitle"
-                defaultMessage="Error loading selected package"
+                defaultMessage="Error loading selected integration"
               />
             }
             error={selectedPkgError}
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx
index 87155afdc21be..1eee9f6b0c346 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx
@@ -138,7 +138,7 @@ export const DatasourcesTable: React.FunctionComponent<Props> = ({
         name: i18n.translate(
           'xpack.ingestManager.configDetails.datasourcesTable.packageNameColumnTitle',
           {
-            defaultMessage: 'Package',
+            defaultMessage: 'Integration',
           }
         ),
         render(packageTitle: string, datasource: InMemoryDatasource) {
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx
index 2ca49298decf9..818b365d5be12 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx
@@ -62,7 +62,7 @@ export function PackageListGrid({
           query={searchTerm}
           box={{
             placeholder: i18n.translate('xpack.ingestManager.epmList.searchPackagesPlaceholder', {
-              defaultMessage: 'Search for a package',
+              defaultMessage: 'Search for integrations',
             }),
             incremental: true,
           }}
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx
index a7204dd722603..d83910f29f1a7 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx
@@ -5,6 +5,7 @@
  */
 import React, { Fragment } from 'react';
 import styled from 'styled-components';
+import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { EuiFlexGroup, EuiFlexItem, EuiPage, EuiTitle, IconType, EuiButton } from '@elastic/eui';
 import { PackageInfo } from '../../../../types';
@@ -41,7 +42,12 @@ export function Header(props: HeaderProps) {
   return (
     <Fragment>
       <FullWidthNavRow>
-        <NavButtonBack href={toListView()} text="Browse Packages" />
+        <NavButtonBack
+          href={toListView()}
+          text={i18n.translate('xpack.ingestManager.epm.browseAllButtonText', {
+            defaultMessage: 'Browse all integrations',
+          })}
+        />
       </FullWidthNavRow>
       <EuiFlexGroup>
         {iconType ? (
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx
index 4230775c04e00..4d6c02eeef8b4 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx
@@ -17,7 +17,7 @@ export const HeroCopy = memo(() => {
           <h1>
             <FormattedMessage
               id="xpack.ingestManager.epm.pageTitle"
-              defaultMessage="Elastic Package Manager"
+              defaultMessage="Elastic Integrations"
             />
           </h1>
         </EuiText>
@@ -27,7 +27,7 @@ export const HeroCopy = memo(() => {
           <p>
             <FormattedMessage
               id="xpack.ingestManager.epm.pageSubtitle"
-              defaultMessage="Browse packages for popular apps and services."
+              defaultMessage="Browse integrations for popular apps and services."
             />
           </p>
         </EuiText>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx
index 5f215b7788259..bf785147502b5 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx
@@ -35,16 +35,16 @@ export function EPMHomePage() {
         ([
           {
             id: 'all_packages',
-            name: i18n.translate('xpack.ingestManager.epmList.allPackagesTabText', {
-              defaultMessage: 'All packages',
+            name: i18n.translate('xpack.ingestManager.epmList.allTabText', {
+              defaultMessage: 'All integrations',
             }),
             href: ALL_PACKAGES_URI,
             isSelected: tabId !== 'installed',
           },
           {
             id: 'installed_packages',
-            name: i18n.translate('xpack.ingestManager.epmList.installedPackagesTabText', {
-              defaultMessage: 'Installed packages',
+            name: i18n.translate('xpack.ingestManager.epmList.installedTabText', {
+              defaultMessage: 'Installed integrations',
             }),
             href: INSTALLED_PACKAGES_URI,
             isSelected: tabId === 'installed',
@@ -72,14 +72,14 @@ function InstalledPackages() {
       ? allPackages.response.filter(pkg => pkg.status === 'installed')
       : [];
 
-  const title = i18n.translate('xpack.ingestManager.epmList.installedPackagesTitle', {
-    defaultMessage: 'Installed packages',
+  const title = i18n.translate('xpack.ingestManager.epmList.installedTitle', {
+    defaultMessage: 'Installed integrations',
   });
 
   const categories = [
     {
       id: '',
-      title: i18n.translate('xpack.ingestManager.epmList.allPackagesFilterLinkText', {
+      title: i18n.translate('xpack.ingestManager.epmList.allFilterLinkText', {
         defaultMessage: 'All',
       }),
       count: packages.length,
@@ -120,8 +120,8 @@ function AvailablePackages() {
   const packages =
     categoryPackagesRes && categoryPackagesRes.response ? categoryPackagesRes.response : [];
 
-  const title = i18n.translate('xpack.ingestManager.epmList.allPackagesTitle', {
-    defaultMessage: 'All packages',
+  const title = i18n.translate('xpack.ingestManager.epmList.allTitle', {
+    defaultMessage: 'All integrations',
   });
 
   const categories = [
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 705a4577cbd07..687834a683c4d 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -8389,7 +8389,6 @@
     "xpack.ingestManager.appNavigation.configurationsLinkText": "構成",
     "xpack.ingestManager.appNavigation.fleetLinkText": "フリート",
     "xpack.ingestManager.appNavigation.overviewLinkText": "概要",
-    "xpack.ingestManager.appNavigation.packagesLinkText": "パッケージ",
     "xpack.ingestManager.appTitle": "Ingest Manager",
     "xpack.ingestManager.configDetails.addDatasourceButtonText": "データソースを作成",
     "xpack.ingestManager.configDetails.configDetailsTitle": "構成「{id}」",
@@ -8515,10 +8514,6 @@
     "xpack.ingestManager.epm.pageSubtitle": "人気のアプリやサービスのパッケージを参照する",
     "xpack.ingestManager.epm.pageTitle": "Elastic Package Manager",
     "xpack.ingestManager.epmList.allPackagesFilterLinkText": "すべて",
-    "xpack.ingestManager.epmList.allPackagesTabText": "すべてのパッケージ",
-    "xpack.ingestManager.epmList.allPackagesTitle": "すべてのパッケージ",
-    "xpack.ingestManager.epmList.installedPackagesTabText": "パッケージをインストールしました",
-    "xpack.ingestManager.epmList.installedPackagesTitle": "パッケージをインストールしました",
     "xpack.ingestManager.epmList.noPackagesFoundPlaceholder": "パッケージが見つかりません",
     "xpack.ingestManager.epmList.searchPackagesPlaceholder": "パッケージを検索",
     "xpack.ingestManager.epmList.updatesAvailableFilterLinkText": "更新が可能です",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 50b807a4934ed..58905787da8d5 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -8392,7 +8392,6 @@
     "xpack.ingestManager.appNavigation.configurationsLinkText": "配置",
     "xpack.ingestManager.appNavigation.fleetLinkText": "Fleet",
     "xpack.ingestManager.appNavigation.overviewLinkText": "概览",
-    "xpack.ingestManager.appNavigation.packagesLinkText": "软件包",
     "xpack.ingestManager.appTitle": "Ingest Manager",
     "xpack.ingestManager.configDetails.addDatasourceButtonText": "创建数据源",
     "xpack.ingestManager.configDetails.configDetailsTitle": "配置“{id}”",
@@ -8518,10 +8517,6 @@
     "xpack.ingestManager.epm.pageSubtitle": "浏览热门应用和服务的软件。",
     "xpack.ingestManager.epm.pageTitle": "Elastic Package Manager",
     "xpack.ingestManager.epmList.allPackagesFilterLinkText": "全部",
-    "xpack.ingestManager.epmList.allPackagesTabText": "所有软件包",
-    "xpack.ingestManager.epmList.allPackagesTitle": "所有软件包",
-    "xpack.ingestManager.epmList.installedPackagesTabText": "已安装软件包",
-    "xpack.ingestManager.epmList.installedPackagesTitle": "已安装软件包",
     "xpack.ingestManager.epmList.noPackagesFoundPlaceholder": "未找到任何软件包",
     "xpack.ingestManager.epmList.searchPackagesPlaceholder": "搜索软件包",
     "xpack.ingestManager.epmList.updatesAvailableFilterLinkText": "有可用更新",

From 59c044ff00d88d63c7bf30685a6f1371c7164f8c Mon Sep 17 00:00:00 2001
From: Kaarina Tungseth <kaarina.tungseth@elastic.co>
Date: Thu, 9 Apr 2020 12:42:30 -0500
Subject: [PATCH 30/78] [DOCS] Removed references to right (#62508)

---
 docs/apm/spans.asciidoc                       |  2 +-
 docs/apm/transactions.asciidoc                |  1 +
 docs/canvas/canvas-share-workpad.asciidoc     |  4 ++--
 docs/canvas/canvas-tutorial.asciidoc          |  6 +++---
 docs/canvas/canvas-workpad.asciidoc           |  2 +-
 .../alerting/alert-management.asciidoc        | 14 ++++++-------
 .../alerting/connector-management.asciidoc    |  8 ++++----
 docs/management/index-patterns.asciidoc       |  1 -
 docs/management/managing-fields.asciidoc      |  2 +-
 .../create_and_manage_rollups.asciidoc        |  4 ++--
 docs/maps/geojson-upload.asciidoc             |  3 +--
 .../indexing-geojson-data-tutorial.asciidoc   |  4 ++--
 docs/maps/maps-getting-started.asciidoc       |  5 ++---
 docs/maps/search.asciidoc                     |  2 +-
 docs/user/alerting/defining-alerts.asciidoc   | 20 +++++++++----------
 docs/user/dashboard.asciidoc                  |  2 +-
 docs/user/discover.asciidoc                   |  2 +-
 docs/user/graph/getting-started.asciidoc      |  4 ++--
 docs/user/monitoring/beats-details.asciidoc   |  4 ++--
 docs/visualize/lens.asciidoc                  | 12 +++++------
 20 files changed, 50 insertions(+), 52 deletions(-)

diff --git a/docs/apm/spans.asciidoc b/docs/apm/spans.asciidoc
index b09de576f2d4a..ef21e1c5333e0 100644
--- a/docs/apm/spans.asciidoc
+++ b/docs/apm/spans.asciidoc
@@ -34,4 +34,4 @@ which indicates the next transaction in the trace.
 These transactions can be expanded and viewed in detail by clicking on them.
 
 After exploring these traces,
-you can return to the full trace by clicking *View full trace* in the upper right hand corner of the page.
+you can return to the full trace by clicking *View full trace*.
diff --git a/docs/apm/transactions.asciidoc b/docs/apm/transactions.asciidoc
index 5c92afa55109d..1eb037009efff 100644
--- a/docs/apm/transactions.asciidoc
+++ b/docs/apm/transactions.asciidoc
@@ -105,6 +105,7 @@ image::apm/images/apm-transaction-duration-dist.png[Example view of transactions
 
 This graph shows a typical distribution, and indicates most of our requests were served quickly - awesome!
 It's the requests on the right, the ones taking longer than average, that we probably want to focus on.
+
 When you select one of these buckets,
 you're presented with up to ten trace samples.
 Each sample has a span timeline waterfall that shows what a typical request in that bucket was doing.
diff --git a/docs/canvas/canvas-share-workpad.asciidoc b/docs/canvas/canvas-share-workpad.asciidoc
index ee29926914ad6..5cae3fcc7b531 100644
--- a/docs/canvas/canvas-share-workpad.asciidoc
+++ b/docs/canvas/canvas-share-workpad.asciidoc
@@ -76,7 +76,7 @@ After you've added the workpad to your website, you can change the autoplay and
 
 To change the autoplay settings:
 
-. In the lower right corner of the shareable workpad, click the settings icon.
+. Click the settings icon.
 
 . Click *Auto Play*, then change the settings.
 +
@@ -85,7 +85,7 @@ image::images/canvas_share_autoplay_480.gif[Autoplay settings]
 
 To change the toolbar settings:
 
-. In the lower right corner, click the settings icon.
+. Click the settings icon.
 
 . Click *Toolbar*, then change the settings.
 +
diff --git a/docs/canvas/canvas-tutorial.asciidoc b/docs/canvas/canvas-tutorial.asciidoc
index b6d684bdf5dde..a38ab4a69598e 100644
--- a/docs/canvas/canvas-tutorial.asciidoc
+++ b/docs/canvas/canvas-tutorial.asciidoc
@@ -18,7 +18,7 @@ Your first step to working with Canvas is to create a workpad.
 
 . Click *Create workpad*.
 
-. To add a *Name* for your workpad, use the editor on the right. For example, `My Canvas Workpad`.
+. To add a *Name* for your workpad, use the editor. For example, `My Canvas Workpad`.
 
 [float]
 === Customize your workpad with images
@@ -29,7 +29,7 @@ To customize your workpad to look the way you want, add your own images.
 +
 The default Elastic logo image appears on your page.
 
-. To replace the Elastic logo with your own image, select the image, then use the editor on the right.
+. To replace the Elastic logo with your own image, select the image, then use the editor.
 
 . To move the image, click and drag it to your preferred location.
 
@@ -73,7 +73,7 @@ You'll notice that the error is gone, but the number could use some formatting.
 
 . To format the number, use the Canvas expression language.
 
-.. In the lower right corner, click *Expression editor*.
+.. Click *Expression editor*.
 +
 You're now looking at the raw data syntax that Canvas uses to display the element.
 
diff --git a/docs/canvas/canvas-workpad.asciidoc b/docs/canvas/canvas-workpad.asciidoc
index c5c163441439c..42eedf55c404d 100644
--- a/docs/canvas/canvas-workpad.asciidoc
+++ b/docs/canvas/canvas-workpad.asciidoc
@@ -124,7 +124,7 @@ Organize your ideas onto separate pages by adding more pages.
 
 . Click *Page 1*, then click *+*.
 
-. On the *Page* editor panel on the right, select the page transition from the *Transition* dropdown.
+. On the *Page* editor panel, select the page transition from the *Transition* dropdown.
 +
 [role="screenshot"]
 image::images/canvas-add-pages.gif[Add pages]
diff --git a/docs/management/alerting/alert-management.asciidoc b/docs/management/alerting/alert-management.asciidoc
index caf260937b7be..73cf40c4d7c40 100644
--- a/docs/management/alerting/alert-management.asciidoc
+++ b/docs/management/alerting/alert-management.asciidoc
@@ -18,9 +18,9 @@ For more information on alerting concepts and the types of alerts and actions av
 [float]
 ==== Finding alerts
 
-The *Alerts* tab lists all alerts in the current space, including summary information about their execution frequency, tags, and type. 
+The *Alerts* tab lists all alerts in the current space, including summary information about their execution frequency, tags, and type.
 
-The *search bar* can be used to quickly find alerts by name or tag. 
+The *search bar* can be used to quickly find alerts by name or tag.
 
 [role="screenshot"]
 image::images/alerts-filter-by-search.png[Filtering the alerts list using the search bar]
@@ -30,7 +30,7 @@ The *type* dropdown lets you filter to a subset of alert types.
 [role="screenshot"]
 image::images/alerts-filter-by-type.png[Filtering the alerts list by types of alert]
 
-The *Action type* dropdown lets you filter by the type of action used in the alert. 
+The *Action type* dropdown lets you filter by the type of action used in the alert.
 
 [role="screenshot"]
 image::images/alerts-filter-by-action-type.png[Filtering the alert list by type of action]
@@ -39,16 +39,16 @@ image::images/alerts-filter-by-action-type.png[Filtering the alert list by type
 [[create-edit-alerts]]
 ==== Creating and editing alerts
 
-Many alerts must be created within the context of a {kib} app like <<xpack-infra, Metrics>>, <<xpack-apm, APM>>, or <<xpack-uptime, Uptime>>, but others are generic. Generic alert types can be created in the *Alerts* management UI by clicking the *Create* button. This will launch a flyout that guides you through selecting an alert type and configuring it's properties. Refer to <<alert-types>> for details on what types of alerts are available and how to configure them. 
+Many alerts must be created within the context of a {kib} app like <<xpack-infra, Metrics>>, <<xpack-apm, APM>>, or <<xpack-uptime, Uptime>>, but others are generic. Generic alert types can be created in the *Alerts* management UI by clicking the *Create* button. This will launch a flyout that guides you through selecting an alert type and configuring it's properties. Refer to <<alert-types>> for details on what types of alerts are available and how to configure them.
 
-After an alert is created, you can re-open the flyout and change an alerts properties by clicking the *Edit* button shown on each row of the alert listing. 
+After an alert is created, you can re-open the flyout and change an alerts properties by clicking the *Edit* button shown on each row of the alert listing.
 
 
 [float]
 [[controlling-alerts]]
 ==== Controlling alerts
 
-The alert listing allows you to quickly mute/unmute, disable/enable, and delete individual alerts by clicking the action button at the right of each row. 
+The alert listing allows you to quickly mute/unmute, disable/enable, and delete individual alerts by clicking the action button. 
 
 [role="screenshot"]
 image:management/alerting/images/individual-mute-disable.png[The actions button allows an individual alert to be muted, disabled, or deleted]
@@ -56,4 +56,4 @@ image:management/alerting/images/individual-mute-disable.png[The actions button
 These operations can also be performed in bulk by multi-selecting alerts and clicking the *Manage alerts* button:
 
 [role="screenshot"]
-image:management/alerting/images/bulk-mute-disable.png[The Manage alerts button lets you mute/unmute, enable/disable, and delete in bulk]
\ No newline at end of file
+image:management/alerting/images/bulk-mute-disable.png[The Manage alerts button lets you mute/unmute, enable/disable, and delete in bulk]
diff --git a/docs/management/alerting/connector-management.asciidoc b/docs/management/alerting/connector-management.asciidoc
index 1002a372f9460..46e106e6e9648 100644
--- a/docs/management/alerting/connector-management.asciidoc
+++ b/docs/management/alerting/connector-management.asciidoc
@@ -15,7 +15,7 @@ image::images/connector-listing.png[Example connector listing in the Alerts and
 [float]
 ==== Connector list
 
-The *Connectors* tab lists all connectors in the current space. The *search bar* can be used to find specific connectors by name and/or type. 
+The *Connectors* tab lists all connectors in the current space. The *search bar* can be used to find specific connectors by name and/or type.
 
 [role="screenshot"]
 image::images/connector-filter-by-search.png[Filtering the connector list using the search bar]
@@ -26,12 +26,12 @@ The *type* dropdown also lets you filter to a subset of action types.
 [role="screenshot"]
 image::images/connector-filter-by-type.png[Filtering the connector list by types of actions]
 
-The *Actions* column indicates the number of actions that reference the connector. This count helps you confirm a connector is unused before you delete it, and tells you how many actions will be affected when a connector is modified. 
+The *Actions* column indicates the number of actions that reference the connector. This count helps you confirm a connector is unused before you delete it, and tells you how many actions will be affected when a connector is modified.
 
 [role="screenshot"]
 image::images/connector-action-count.png[Filtering the connector list by types of actions]
 
-You can delete individual connectors using the trash icon on the right of each row. Connectors can also be deleted in bulk by multi-selecting them and clicking the *Delete* button to the left of the search box. 
+You can delete individual connectors using the trash icon. Connectors can also be deleted in bulk by multi-selecting them and clicking the *Delete* button to the left of the search box. 
 
 [role="screenshot"]
 image::images/connector-delete.png[Deleting connectors individually or in bulk]
@@ -44,4 +44,4 @@ When this happens the action will fail to execute, and appear as errors in the {
 
 ==== Creating a new connector
 
-New connectors can be created by clicking the *Create connector* button, which will guide you to select the type of connector and configure it's properties. Refer to <<action-types>> for the types of connectors available and how to configure them. Once you create a connector it will be made available to you anytime you set up an action in the current space.
\ No newline at end of file
+New connectors can be created by clicking the *Create connector* button, which will guide you to select the type of connector and configure it's properties. Refer to <<action-types>> for the types of connectors available and how to configure them. Once you create a connector it will be made available to you anytime you set up an action in the current space.
diff --git a/docs/management/index-patterns.asciidoc b/docs/management/index-patterns.asciidoc
index 45f8bd13a5c54..bb16faab7fe5a 100644
--- a/docs/management/index-patterns.asciidoc
+++ b/docs/management/index-patterns.asciidoc
@@ -38,7 +38,6 @@ image:management/index-patterns/images/rollup-index-pattern.png["Menu with rollu
 Just start typing in the *Index pattern* field, and {kib} looks for
 the names of {es} indices that match your input. Make sure that the name of the
 index pattern is unique.
-To include system indices in your search, toggle the switch in the upper right.
 
 [role="screenshot"]
 image:management/index-patterns/images/create-index-pattern.png["Create index pattern"]
diff --git a/docs/management/managing-fields.asciidoc b/docs/management/managing-fields.asciidoc
index 1a1bcec10ab50..9682d918aabe4 100644
--- a/docs/management/managing-fields.asciidoc
+++ b/docs/management/managing-fields.asciidoc
@@ -25,7 +25,7 @@ the *Index patterns* overview.
 [role="screenshot"]
 image::management/index-patterns/images/new-index-pattern.png["Index files and data types"]
 
-Use the icons in the upper right to perform the following actions:
+Use the icons to perform the following actions:
 
 * [[set-default-pattern]]*Set the default index pattern.* {kib} uses a badge to make users
 aware of which index pattern is the default. The first pattern
diff --git a/docs/management/rollups/create_and_manage_rollups.asciidoc b/docs/management/rollups/create_and_manage_rollups.asciidoc
index 6a56970687fd6..da2e190847fdb 100644
--- a/docs/management/rollups/create_and_manage_rollups.asciidoc
+++ b/docs/management/rollups/create_and_manage_rollups.asciidoc
@@ -42,8 +42,8 @@ image::images/management_create_rollup_job.png[][Wizard that walks you through c
 === Start, stop, and delete rollup jobs
 
 Once you’ve saved a rollup job, you’ll see it the *Rollup Jobs* overview page,
-where you can drill down for further investigation. The *Manage* menu in
-the lower right enables you to start, stop, and delete the rollup job.
+where you can drill down for further investigation. The *Manage* menu enables
+you to start, stop, and delete the rollup job.
 You must first stop a rollup job before deleting it.
 
 [role="screenshot"]
diff --git a/docs/maps/geojson-upload.asciidoc b/docs/maps/geojson-upload.asciidoc
index ad20264f56138..7e2cdddfd30ef 100644
--- a/docs/maps/geojson-upload.asciidoc
+++ b/docs/maps/geojson-upload.asciidoc
@@ -37,7 +37,6 @@ the Elasticsearch responses are shown on the *Layer add panel* and the indexed d
 appears on the map. The geospatial data on the map
 should be identical to the locally-previewed data, but now it's indexed data from Elasticsearch.
 
-. To continue adding data to the map, click *Add layer* in the lower
-right-hand corner.
+. To continue adding data to the map, click *Add layer*.
 . In *Layer settings*, adjust any settings or <<maps-vector-style-properties, properties>> as needed.
 . Click *Save & close*.
diff --git a/docs/maps/indexing-geojson-data-tutorial.asciidoc b/docs/maps/indexing-geojson-data-tutorial.asciidoc
index a94e5757d5dfa..bf846a2b80e03 100644
--- a/docs/maps/indexing-geojson-data-tutorial.asciidoc
+++ b/docs/maps/indexing-geojson-data-tutorial.asciidoc
@@ -55,14 +55,14 @@ auto-populate *Index type* with either {ref}/geo-point.html[geo_point] or
  {ref}/geo-shape.html[geo_shape] and *Index name* with
 `<file name>`.
 
-. Click *Import file* in the lower right.
+. Click *Import file*.
 +
 You'll see activity as the GeoJSON Upload utility creates a new index
 and index pattern for the data set. When the process is complete, you should
 receive messages that the creation of the new index and index pattern
 were successful.
 
-. Click *Add layer* in the bottom right.
+. Click *Add layer*.
 
 . In *Layer settings*, adjust settings and <<maps-vector-style-properties, properties>> as needed.
 . Click *Save & close*.
diff --git a/docs/maps/maps-getting-started.asciidoc b/docs/maps/maps-getting-started.asciidoc
index b13eeebe56fd8..6495b8a057cf6 100644
--- a/docs/maps/maps-getting-started.asciidoc
+++ b/docs/maps/maps-getting-started.asciidoc
@@ -80,7 +80,7 @@ To symbolize countries by web traffic, you'll need to augment the world country
 To do this, you'll create a <<terms-join, term join>> to link the vector source *World Countries* to
 the {es} index `kibana_sample_data_logs` on the shared key iso2 = geo.src.
 
-. Click plus image:maps/images/gs_plus_icon.png[] to the right of *Term Joins* label.
+. Click plus image:maps/images/gs_plus_icon.png[] next to the *Term Joins* label.
 . Click *Join --select--*
 . Set *Left field* to *ISO 3166-1 alpha-2 code*.
 . Set *Right source* to *kibana_sample_data_logs*.
@@ -238,7 +238,7 @@ The *machine.os.keyword: osx* filter appears in the dashboard query bar.
 +
 . Click the *x* to remove the *machine.os.keyword: osx* filter.
 . In the map, click in the United States vector.
-. Click plus image:maps/images/gs_plus_icon.png[] to the right of *iso2* row in the tooltip.
+. Click plus image:maps/images/gs_plus_icon.png[] next to the *iso2* row in the tooltip.
 +
 Both the visualizations and the map are filtered to only show documents where *geo.src* is *US*.
 The *geo.src: US* filter appears in the dashboard query bar.
@@ -247,4 +247,3 @@ Your dashboard should look like this:
 +
 [role="screenshot"]
 image::maps/images/gs_dashboard_with_terms_filter.png[]
-
diff --git a/docs/maps/search.asciidoc b/docs/maps/search.asciidoc
index 8a93352798d2c..a461ab6fbb3a6 100644
--- a/docs/maps/search.asciidoc
+++ b/docs/maps/search.asciidoc
@@ -4,7 +4,7 @@
 
 **Elastic Maps** embeds the search bar for real-time search.
 Only layers requesting data from {es} are filtered when you submit a search request.
-Layers narrowed by the search context contain the filter icon image:maps/images/filter_icon.png[] to the right of layer name in the legend.
+Layers narrowed by the search context contain the filter icon image:maps/images/filter_icon.png[] next to the layer name in the legend.
 
 You can create a layer that requests data from {es} from the following:
 
diff --git a/docs/user/alerting/defining-alerts.asciidoc b/docs/user/alerting/defining-alerts.asciidoc
index 89c4c88708d58..f05afac34e595 100644
--- a/docs/user/alerting/defining-alerts.asciidoc
+++ b/docs/user/alerting/defining-alerts.asciidoc
@@ -2,7 +2,7 @@
 [[defining-alerts]]
 == Defining alerts
 
-{kib} alerts can be created in a variety of apps including <<xpack-apm,*APM*>>, <<xpack-infra,*Metrics*>>, <<xpack-siem,*SIEM*>>, <<xpack-uptime,*Uptime*>> and from <<management,*Management*>> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail. 
+{kib} alerts can be created in a variety of apps including <<xpack-apm,*APM*>>, <<xpack-infra,*Metrics*>>, <<xpack-siem,*SIEM*>>, <<xpack-uptime,*Uptime*>> and from <<management,*Management*>> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail.
 
 [float]
 === Alert flyout
@@ -25,20 +25,20 @@ All alert share the following four properties in common:
 image::images/alert-flyout-general-details.png[All alerts have name, tags, check every, and re-notify every properties in common]
 
 Name::      The name of the alert. While this name does not have to be unique, the name can be referenced in actions and also appears in the searchable alert listing in the management UI. A distinctive name can help identify and find an alert.
-Tags::      A list of tag names that can be applied to an alert. Tags can help you organize and find alerts, because tags appear in the alert listing in the management UI which is searchable by tag.  
+Tags::      A list of tag names that can be applied to an alert. Tags can help you organize and find alerts, because tags appear in the alert listing in the management UI which is searchable by tag.
 Check every::      This value determines how frequently the alert conditions below are checked. Note that the timing of background alert checks are not guaranteed, particularly for intervals of less than 10 seconds. See <<alerting-scale-performance>> for more information.
-Re-notify every::      This value limits how often actions are repeated when an alert instance remains active across alert checks. See <<alerting-concepts-suppressing-duplicate-notifications>> for more information.  
+Re-notify every::      This value limits how often actions are repeated when an alert instance remains active across alert checks. See <<alerting-concepts-suppressing-duplicate-notifications>> for more information.
 
 [float]
 [[defining-alerts-type-conditions]]
 === Alert type and conditions
 
-Depending upon the {kib} app and context, you may be prompted to choose the type of alert you wish to create. Some apps will pre-select the type of alert for you. 
+Depending upon the {kib} app and context, you may be prompted to choose the type of alert you wish to create. Some apps will pre-select the type of alert for you.
 
 [role="screenshot"]
 image::images/alert-flyout-alert-type-selection.png[Choosing the type of alert to create]
 
-Each alert type provides its own way of defining the conditions to detect, but an expression formed by a series of clauses is a common pattern. Each clause has a UI control that allows you to define the clause. For example, in an index threshold alert the `WHEN` clause allows you to select an aggregation operation to apply to a numeric field. 
+Each alert type provides its own way of defining the conditions to detect, but an expression formed by a series of clauses is a common pattern. Each clause has a UI control that allows you to define the clause. For example, in an index threshold alert the `WHEN` clause allows you to select an aggregation operation to apply to a numeric field.
 
 [role="screenshot"]
 image::images/alert-flyout-alert-conditions.png[UI for defining alert conditions on an index threshold alert]
@@ -52,19 +52,19 @@ To add an action to an alert, you first select the type of action:
 [role="screenshot"]
 image::images/alert-flyout-action-type-selection.png[UI for selecting an action type]
 
-Each action  must specify a <<alerting-concepts-connectors, connector>> instance. If no connectors exist for that action type, click "Add new" to create one.  
+Each action  must specify a <<alerting-concepts-connectors, connector>> instance. If no connectors exist for that action type, click "Add new" to create one.
 
-Each action type exposes different properties. For example an email action allows you to set the recipients, the subject, and a message body in markdown format. See <<action-types>> for details on the types of actions provided by {kib} and their properties. 
+Each action type exposes different properties. For example an email action allows you to set the recipients, the subject, and a message body in markdown format. See <<action-types>> for details on the types of actions provided by {kib} and their properties.
 
 [role="screenshot"]
 image::images/alert-flyout-action-details.png[UI for defining an email action]
 
-Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. Available variables differ by alert type, and a list can be accessed using the "add variable" button at the right of the text box.
+Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. Available variables differ by alert type, and a list can be accessed using the "add variable" button.
 
 [role="screenshot"]
 image::images/alert-flyout-action-variables.png[Passing alert values to an action]
 
-You can attach more than one action. Clicking the "Add action" button will prompt you to select another alert type and repeat the above steps again. 
+You can attach more than one action. Clicking the "Add action" button will prompt you to select another alert type and repeat the above steps again.
 
 [role="screenshot"]
 image::images/alert-flyout-add-action.png[You can add multiple actions on an alert]
@@ -77,4 +77,4 @@ Actions are not required on alerts. In some cases you may want to run an alert w
 [float]
 === Managing alerts
 
-To modify an alert after it was created, including muting or disabling it, use the <<alert-management, alert listing in the Management UI>>.
\ No newline at end of file
+To modify an alert after it was created, including muting or disabling it, use the <<alert-management, alert listing in the Management UI>>.
diff --git a/docs/user/dashboard.asciidoc b/docs/user/dashboard.asciidoc
index a17e46c5b3542..ab529a533d5e3 100644
--- a/docs/user/dashboard.asciidoc
+++ b/docs/user/dashboard.asciidoc
@@ -90,7 +90,7 @@ In *Edit* mode, you can move, resize, customize, and delete panels to suit your
 * To move a panel, click and hold the panel header and drag to the new location.
 
 [[resizing-containers]]
-* To resize a panel, click the resize control on the lower right and drag
+* To resize a panel, click the resize control and drag
 to the new dimensions.
 
 * To toggle the use of margins and panel titles, use the *Options* menu.
diff --git a/docs/user/discover.asciidoc b/docs/user/discover.asciidoc
index 4222ba40debb7..2547b38a22616 100644
--- a/docs/user/discover.asciidoc
+++ b/docs/user/discover.asciidoc
@@ -33,7 +33,7 @@ which has a pre-built index pattern.
 
 By default, *Discover* shows data for the last 15 minutes.
 If you have a time-based index, and no data displays,
-you might need to increase the time range. Using the <<set-time-filter, time filter>> in the upper right,
+you might need to increase the time range. Using the <<set-time-filter, time filter>>,
 you can specify a common or recently-used time range, a relative time
 from now, or an absolute time range.
 
diff --git a/docs/user/graph/getting-started.asciidoc b/docs/user/graph/getting-started.asciidoc
index 1749678ace9e3..a155017f1bb22 100644
--- a/docs/user/graph/getting-started.asciidoc
+++ b/docs/user/graph/getting-started.asciidoc
@@ -38,7 +38,7 @@ image::user/graph/images/graph-url-connections.png["URL connections"]
 [role="screenshot"]
 image::user/graph/images/graph-link-summary.png["Link summary"]
 
-. Use the control bar on the right to explore
+. Use the control bar to explore
 additional connections:
 +
 * To display additional vertices that connect to your graph, click the expand icon
@@ -70,7 +70,7 @@ select *Edit settings*.
 
 To change the color and label of selected vertices,
 click the style icon image:user/graph/images/graph-style-button.png[Style]
-in the control bar on the right.
+in the control bar.
 
 
 [float]
diff --git a/docs/user/monitoring/beats-details.asciidoc b/docs/user/monitoring/beats-details.asciidoc
index 0b2be4dd9e3d9..f4ecb2a74d91e 100644
--- a/docs/user/monitoring/beats-details.asciidoc
+++ b/docs/user/monitoring/beats-details.asciidoc
@@ -14,8 +14,8 @@ image::user/monitoring/images/monitoring-beats.jpg["Monitoring Beats",link="imag
 To view an overview of the Beats data in the cluster, click *Overview*. The
 overview page has a section for activity in the last day, which is a real-time
 sample of data. The summary bar and charts follow the typical paradigm
-of data in the Monitoring UI, which is bound to the span of the time filter in
-the top right corner of the page. This overview page can therefore show
+of data in the Monitoring UI, which is bound to the span of the time filter.
+This overview page can therefore show
 up-to-date or historical information.
 
 To view a listing of the individual Beat instances in the cluster, click *Beats*.
diff --git a/docs/visualize/lens.asciidoc b/docs/visualize/lens.asciidoc
index 35570ea7ca1dc..b181763c0d0d0 100644
--- a/docs/visualize/lens.asciidoc
+++ b/docs/visualize/lens.asciidoc
@@ -38,7 +38,7 @@ you'll see two places highlighted in green:
 
 * The visualization builder pane
 
-* The *X-axis* or *Y-axis* fields in the right column
+* The *X-axis* or *Y-axis* fields
 
 You can incorporate many fields into your visualization, and Lens uses heuristics to decide how
 to apply each one to the visualization.
@@ -89,8 +89,8 @@ You can switch between suggestions without losing your previous state:
 [role="screenshot"]
 image::images/lens_suggestions.gif[]
 
-If you want to switch to a chart type that is not suggested, click the chart type in the
-top right, then select a chart type. When there is an exclamation point (!)
+If you want to switch to a chart type that is not suggested, click the chart type,
+then select a chart type. When there is an exclamation point (!)
 next to a chart type, Lens is unable to transfer your current data, but
 still allows you to make the change.
 
@@ -106,7 +106,7 @@ If there is a match, Lens displays the new data. All fields that do not match th
 
 . Change the data field options, such as the aggregation or label.
 
-.. Click *Drop a field here* or the field name in the right column.
+.. Click *Drop a field here* or the field name in the column.
 
 .. Change the options that appear depending on the type of field.
 
@@ -168,7 +168,7 @@ image::images/lens_tutorial_2.png[Lens tutorial]
 
 Customize your visualization to look exactly how you want.
 
-. In the right column, click *Average of taxful_total_price*.
+. Click *Average of taxful_total_price*.
 
 .. Change the *Label* to `Sales`, or a name that you prefer for the data.
 
@@ -180,7 +180,7 @@ six available categories.
 . Look at the suggestions. None of them show an area chart, but for sales data, a stacked area chart
 might make sense. To switch the chart type:
 
-.. Click *Stacked bar chart* in the right column.
+.. Click *Stacked bar chart* in the column.
 
 .. Click *Stacked area*.
 +

From bc3f38288337220fba91c32de3ed5a14e9c219cc Mon Sep 17 00:00:00 2001
From: spalger <spalger@users.noreply.github.com>
Date: Thu, 9 Apr 2020 10:47:42 -0700
Subject: [PATCH 31/78] skip flaky suite (#62927)

---
 x-pack/test/functional/apps/canvas/custom_elements.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/x-pack/test/functional/apps/canvas/custom_elements.ts b/x-pack/test/functional/apps/canvas/custom_elements.ts
index 6c34556840960..de3976509be1f 100644
--- a/x-pack/test/functional/apps/canvas/custom_elements.ts
+++ b/x-pack/test/functional/apps/canvas/custom_elements.ts
@@ -19,7 +19,8 @@ export default function canvasCustomElementTest({
   const PageObjects = getPageObjects(['canvas', 'common']);
   const find = getService('find');
 
-  describe('custom elements', function() {
+  // FLAKY: https://github.com/elastic/kibana/issues/62927
+  describe.skip('custom elements', function() {
     this.tags('skipFirefox');
 
     before(async () => {

From 2574d0f8055981e4a44416dcfea2a9b9b64c5d9b Mon Sep 17 00:00:00 2001
From: Joel Griffith <joel.griffith@elastic.co>
Date: Thu, 9 Apr 2020 11:01:25 -0700
Subject: [PATCH 32/78] Adds a new config flag to encode with BOM for our CSVs
 (#63006)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Adds a new config flag to encode with BOM for our CSVs

* Push out bom-chars to it's own constant

* Getting those snapshots back into shape 💪

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../__snapshots__/index.test.js.snap          |  4 ++
 .../plugins/reporting/common/constants.ts     |  1 +
 x-pack/legacy/plugins/reporting/config.ts     |  1 +
 .../csv/server/execute_job.test.js            | 45 +++++++++++++++++++
 .../export_types/csv/server/execute_job.ts    |  6 ++-
 .../plugins/reporting/server/config/index.ts  |  1 +
 6 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap b/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap
index 757677f1d4f82..3ae3079da136b 100644
--- a/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap
+++ b/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap
@@ -66,6 +66,7 @@ Object {
       "duration": "30s",
       "size": 500,
     },
+    "useByteOrderMarkEncoding": false,
   },
   "enabled": true,
   "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -162,6 +163,7 @@ Object {
       "duration": "30s",
       "size": 500,
     },
+    "useByteOrderMarkEncoding": false,
   },
   "enabled": true,
   "index": ".reporting",
@@ -257,6 +259,7 @@ Object {
       "duration": "30s",
       "size": 500,
     },
+    "useByteOrderMarkEncoding": false,
   },
   "enabled": true,
   "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -353,6 +356,7 @@ Object {
       "duration": "30s",
       "size": 500,
     },
+    "useByteOrderMarkEncoding": false,
   },
   "enabled": true,
   "index": ".reporting",
diff --git a/x-pack/legacy/plugins/reporting/common/constants.ts b/x-pack/legacy/plugins/reporting/common/constants.ts
index 8f7a06ba9f8e9..e3d6a4274e7df 100644
--- a/x-pack/legacy/plugins/reporting/common/constants.ts
+++ b/x-pack/legacy/plugins/reporting/common/constants.ts
@@ -19,6 +19,7 @@ export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv
 
 export const CONTENT_TYPE_CSV = 'text/csv';
 export const CSV_REPORTING_ACTION = 'downloadCsvReport';
+export const CSV_BOM_CHARS = '\ufeff';
 
 export const WHITELISTED_JOB_CONTENT_TYPES = [
   'application/json',
diff --git a/x-pack/legacy/plugins/reporting/config.ts b/x-pack/legacy/plugins/reporting/config.ts
index 211fa70301bbf..5eceb84c83e43 100644
--- a/x-pack/legacy/plugins/reporting/config.ts
+++ b/x-pack/legacy/plugins/reporting/config.ts
@@ -135,6 +135,7 @@ export async function config(Joi: any) {
         .default(),
     }).default(),
     csv: Joi.object({
+      useByteOrderMarkEncoding: Joi.boolean().default(false),
       checkForFormulas: Joi.boolean().default(true),
       enablePanelActionDownload: Joi.boolean().default(true),
       maxSizeBytes: Joi.number()
diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js
index 93dbe598b367c..4870e1e35cdaf 100644
--- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js
+++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js
@@ -13,6 +13,7 @@ import { createMockReportingCore } from '../../../test_helpers';
 import { LevelLogger } from '../../../server/lib/level_logger';
 import { setFieldFormats } from '../../../server/services';
 import { executeJobFactory } from './execute_job';
+import { CSV_BOM_CHARS } from '../../../common/constants';
 
 const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
 
@@ -374,6 +375,50 @@ describe('CSV Execute Job', function() {
     });
   });
 
+  describe('Byte order mark encoding', () => {
+    it('encodes CSVs with BOM', async () => {
+      configGetStub.withArgs('csv', 'useByteOrderMarkEncoding').returns(true);
+      callAsCurrentUserStub.onFirstCall().returns({
+        hits: {
+          hits: [{ _source: { one: 'one', two: 'bar' } }],
+        },
+        _scroll_id: 'scrollId',
+      });
+
+      const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
+      const jobParams = {
+        headers: encryptedHeaders,
+        fields: ['one', 'two'],
+        conflictedTypesFields: [],
+        searchRequest: { index: null, body: null },
+      };
+      const { content } = await executeJob('job123', jobParams, cancellationToken);
+
+      expect(content).toEqual(`${CSV_BOM_CHARS}one,two\none,bar\n`);
+    });
+
+    it('encodes CSVs without BOM', async () => {
+      configGetStub.withArgs('csv', 'useByteOrderMarkEncoding').returns(false);
+      callAsCurrentUserStub.onFirstCall().returns({
+        hits: {
+          hits: [{ _source: { one: 'one', two: 'bar' } }],
+        },
+        _scroll_id: 'scrollId',
+      });
+
+      const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
+      const jobParams = {
+        headers: encryptedHeaders,
+        fields: ['one', 'two'],
+        conflictedTypesFields: [],
+        searchRequest: { index: null, body: null },
+      };
+      const { content } = await executeJob('job123', jobParams, cancellationToken);
+
+      expect(content).toEqual('one,two\none,bar\n');
+    });
+  });
+
   describe('Elasticsearch call errors', function() {
     it('should reject Promise if search call errors out', async function() {
       callAsCurrentUserStub.rejects(new Error());
diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts
index 3a282eb0b2974..376a398da274f 100644
--- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts
+++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts
@@ -7,7 +7,7 @@
 import { i18n } from '@kbn/i18n';
 import Hapi from 'hapi';
 import { IUiSettingsClient, KibanaRequest } from '../../../../../../../src/core/server';
-import { CSV_JOB_TYPE } from '../../../common/constants';
+import { CSV_JOB_TYPE, CSV_BOM_CHARS } from '../../../common/constants';
 import { ReportingCore } from '../../../server/core';
 import { cryptoFactory } from '../../../server/lib';
 import { getFieldFormats } from '../../../server/services';
@@ -121,6 +121,8 @@ export const executeJobFactory: ExecuteJobFactory<ESQueueWorkerExecuteFn<
     ]);
 
     const generateCsv = createGenerateCsv(jobLogger);
+    const bom = config.get('csv', 'useByteOrderMarkEncoding') ? CSV_BOM_CHARS : '';
+
     const { content, maxSizeReached, size, csvContainsFormulas } = await generateCsv({
       searchRequest,
       fields,
@@ -139,7 +141,7 @@ export const executeJobFactory: ExecuteJobFactory<ESQueueWorkerExecuteFn<
 
     return {
       content_type: 'text/csv',
-      content,
+      content: bom + content,
       max_size_reached: maxSizeReached,
       size,
       csv_contains_formulas: csvContainsFormulas,
diff --git a/x-pack/legacy/plugins/reporting/server/config/index.ts b/x-pack/legacy/plugins/reporting/server/config/index.ts
index 623d3c2015f3b..b7b67b57932eb 100644
--- a/x-pack/legacy/plugins/reporting/server/config/index.ts
+++ b/x-pack/legacy/plugins/reporting/server/config/index.ts
@@ -108,6 +108,7 @@ export interface ReportingConfigType {
     enablePanelActionDownload: boolean;
     checkForFormulas: boolean;
     maxSizeBytes: number;
+    useByteOrderMarkEncoding: boolean;
   };
   encryptionKey: string;
   kibanaServer: any;

From 38f7bfb133f017939f3ed1d4b6f04bbf736ac206 Mon Sep 17 00:00:00 2001
From: Christos Nasikas <christos.nasikas@elastic.co>
Date: Thu, 9 Apr 2020 21:26:13 +0300
Subject: [PATCH 33/78] [SIEM][CASE] Test configuration API and hooks (#62803)

* Test API

* Test useConnectors

* Test useConfigure

* Fixes
---
 .../case/configure/__mocks__/api.ts           |  31 ++
 .../containers/case/configure/api.test.ts     | 115 +++++++
 .../public/containers/case/configure/mock.ts  |  99 ++++++
 .../case/configure/use_configure.test.tsx     | 299 ++++++++++++++++++
 .../case/configure/use_configure.tsx          |   2 +-
 .../case/configure/use_connectors.test.tsx    |  95 ++++++
 6 files changed, 640 insertions(+), 1 deletion(-)
 create mode 100644 x-pack/legacy/plugins/siem/public/containers/case/configure/__mocks__/api.ts
 create mode 100644 x-pack/legacy/plugins/siem/public/containers/case/configure/api.test.ts
 create mode 100644 x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts
 create mode 100644 x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.test.tsx

diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/__mocks__/api.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/__mocks__/api.ts
new file mode 100644
index 0000000000000..03f7d241e5dff
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/__mocks__/api.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import {
+  CasesConfigurePatch,
+  CasesConfigureRequest,
+  Connector,
+} from '../../../../../../../../plugins/case/common/api';
+
+import { ApiProps } from '../../types';
+import { CaseConfigure } from '../types';
+import { connectorsMock, caseConfigurationCamelCaseResponseMock } from '../mock';
+
+export const fetchConnectors = async ({ signal }: ApiProps): Promise<Connector[]> =>
+  Promise.resolve(connectorsMock);
+
+export const getCaseConfigure = async ({ signal }: ApiProps): Promise<CaseConfigure> =>
+  Promise.resolve(caseConfigurationCamelCaseResponseMock);
+
+export const postCaseConfigure = async (
+  caseConfiguration: CasesConfigureRequest,
+  signal: AbortSignal
+): Promise<CaseConfigure> => Promise.resolve(caseConfigurationCamelCaseResponseMock);
+
+export const patchCaseConfigure = async (
+  caseConfiguration: CasesConfigurePatch,
+  signal: AbortSignal
+): Promise<CaseConfigure> => Promise.resolve(caseConfigurationCamelCaseResponseMock);
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/api.test.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/api.test.ts
new file mode 100644
index 0000000000000..ef0e51fb1c24d
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/api.test.ts
@@ -0,0 +1,115 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { KibanaServices } from '../../../lib/kibana';
+import { fetchConnectors, getCaseConfigure, postCaseConfigure, patchCaseConfigure } from './api';
+import {
+  connectorsMock,
+  caseConfigurationMock,
+  caseConfigurationResposeMock,
+  caseConfigurationCamelCaseResponseMock,
+} from './mock';
+
+const abortCtrl = new AbortController();
+const mockKibanaServices = KibanaServices.get as jest.Mock;
+jest.mock('../../../lib/kibana');
+
+const fetchMock = jest.fn();
+mockKibanaServices.mockReturnValue({ http: { fetch: fetchMock } });
+
+describe('Case Configuration API', () => {
+  describe('fetch connectors', () => {
+    beforeEach(() => {
+      fetchMock.mockClear();
+      fetchMock.mockResolvedValue(connectorsMock);
+    });
+
+    test('check url, method, signal', async () => {
+      await fetchConnectors({ signal: abortCtrl.signal });
+      expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure/connectors/_find', {
+        method: 'GET',
+        signal: abortCtrl.signal,
+      });
+    });
+
+    test('happy path', async () => {
+      const resp = await fetchConnectors({ signal: abortCtrl.signal });
+      expect(resp).toEqual(connectorsMock);
+    });
+  });
+
+  describe('fetch configuration', () => {
+    beforeEach(() => {
+      fetchMock.mockClear();
+      fetchMock.mockResolvedValue(caseConfigurationResposeMock);
+    });
+
+    test('check url, method, signal', async () => {
+      await getCaseConfigure({ signal: abortCtrl.signal });
+      expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure', {
+        method: 'GET',
+        signal: abortCtrl.signal,
+      });
+    });
+
+    test('happy path', async () => {
+      const resp = await getCaseConfigure({ signal: abortCtrl.signal });
+      expect(resp).toEqual(caseConfigurationCamelCaseResponseMock);
+    });
+
+    test('return null on empty response', async () => {
+      fetchMock.mockResolvedValue({});
+      const resp = await getCaseConfigure({ signal: abortCtrl.signal });
+      expect(resp).toBe(null);
+    });
+  });
+
+  describe('create configuration', () => {
+    beforeEach(() => {
+      fetchMock.mockClear();
+      fetchMock.mockResolvedValue(caseConfigurationResposeMock);
+    });
+
+    test('check url, body, method, signal', async () => {
+      await postCaseConfigure(caseConfigurationMock, abortCtrl.signal);
+      expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure', {
+        body:
+          '{"connector_id":"123","connector_name":"My Connector","closure_type":"close-by-user"}',
+        method: 'POST',
+        signal: abortCtrl.signal,
+      });
+    });
+
+    test('happy path', async () => {
+      const resp = await postCaseConfigure(caseConfigurationMock, abortCtrl.signal);
+      expect(resp).toEqual(caseConfigurationCamelCaseResponseMock);
+    });
+  });
+
+  describe('update configuration', () => {
+    beforeEach(() => {
+      fetchMock.mockClear();
+      fetchMock.mockResolvedValue(caseConfigurationResposeMock);
+    });
+
+    test('check url, body, method, signal', async () => {
+      await patchCaseConfigure({ connector_id: '456', version: 'WzHJ12' }, abortCtrl.signal);
+      expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure', {
+        body: '{"connector_id":"456","version":"WzHJ12"}',
+        method: 'PATCH',
+        signal: abortCtrl.signal,
+      });
+    });
+
+    test('happy path', async () => {
+      const resp = await patchCaseConfigure(
+        { connector_id: '456', version: 'WzHJ12' },
+        abortCtrl.signal
+      );
+      expect(resp).toEqual(caseConfigurationCamelCaseResponseMock);
+    });
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts
new file mode 100644
index 0000000000000..d2491b39fdf56
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import {
+  Connector,
+  CasesConfigureResponse,
+  CasesConfigureRequest,
+} from '../../../../../../../plugins/case/common/api';
+import { CaseConfigure } from './types';
+
+export const connectorsMock: Connector[] = [
+  {
+    id: '123',
+    actionTypeId: '.servicenow',
+    name: 'My Connector',
+    config: {
+      apiUrl: 'https://instance1.service-now.com',
+      casesConfiguration: {
+        mapping: [
+          {
+            source: 'title',
+            target: 'short_description',
+            actionType: 'overwrite',
+          },
+          {
+            source: 'description',
+            target: 'description',
+            actionType: 'append',
+          },
+          {
+            source: 'comments',
+            target: 'comments',
+            actionType: 'append',
+          },
+        ],
+      },
+    },
+    isPreconfigured: true,
+  },
+  {
+    id: '456',
+    actionTypeId: '.servicenow',
+    name: 'My Connector 2',
+    config: {
+      apiUrl: 'https://instance2.service-now.com',
+      casesConfiguration: {
+        mapping: [
+          {
+            source: 'title',
+            target: 'short_description',
+            actionType: 'overwrite',
+          },
+          {
+            source: 'description',
+            target: 'description',
+            actionType: 'overwrite',
+          },
+          {
+            source: 'comments',
+            target: 'comments',
+            actionType: 'append',
+          },
+        ],
+      },
+    },
+    isPreconfigured: true,
+  },
+];
+
+export const caseConfigurationResposeMock: CasesConfigureResponse = {
+  created_at: '2020-04-06T13:03:18.657Z',
+  created_by: { username: 'elastic', full_name: 'Elastic', email: 'elastic@elastic.co' },
+  connector_id: '123',
+  connector_name: 'My Connector',
+  closure_type: 'close-by-user',
+  updated_at: '2020-04-06T14:03:18.657Z',
+  updated_by: { username: 'elastic', full_name: 'Elastic', email: 'elastic@elastic.co' },
+  version: 'WzHJ12',
+};
+
+export const caseConfigurationMock: CasesConfigureRequest = {
+  connector_id: '123',
+  connector_name: 'My Connector',
+  closure_type: 'close-by-user',
+};
+
+export const caseConfigurationCamelCaseResponseMock: CaseConfigure = {
+  createdAt: '2020-04-06T13:03:18.657Z',
+  createdBy: { username: 'elastic', fullName: 'Elastic', email: 'elastic@elastic.co' },
+  connectorId: '123',
+  connectorName: 'My Connector',
+  closureType: 'close-by-user',
+  updatedAt: '2020-04-06T14:03:18.657Z',
+  updatedBy: { username: 'elastic', fullName: 'Elastic', email: 'elastic@elastic.co' },
+  version: 'WzHJ12',
+};
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx
new file mode 100644
index 0000000000000..3ee16e19eaf9f
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx
@@ -0,0 +1,299 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { renderHook, act } from '@testing-library/react-hooks';
+import { useCaseConfigure, ReturnUseCaseConfigure, PersistCaseConfigure } from './use_configure';
+import { caseConfigurationCamelCaseResponseMock } from './mock';
+import * as api from './api';
+
+jest.mock('./api');
+
+const configuration: PersistCaseConfigure = {
+  connectorId: '456',
+  connectorName: 'My Connector 2',
+  closureType: 'close-by-pushing',
+};
+
+describe('useConfigure', () => {
+  beforeEach(() => {
+    jest.clearAllMocks();
+    jest.restoreAllMocks();
+  });
+
+  const args = {
+    setConnector: jest.fn(),
+    setClosureType: jest.fn(),
+    setCurrentConfiguration: jest.fn(),
+  };
+
+  test('init', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      expect(result.current).toEqual({
+        loading: true,
+        persistLoading: false,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+
+  test('fetch case configuration', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(result.current).toEqual({
+        loading: false,
+        persistLoading: false,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+
+  test('fetch case configuration - setConnector', async () => {
+    await act(async () => {
+      const { waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(args.setConnector).toHaveBeenCalledWith('123', 'My Connector');
+    });
+  });
+
+  test('fetch case configuration - setClosureType', async () => {
+    await act(async () => {
+      const { waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(args.setClosureType).toHaveBeenCalledWith('close-by-user');
+    });
+  });
+
+  test('fetch case configuration - setCurrentConfiguration', async () => {
+    await act(async () => {
+      const { waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(args.setCurrentConfiguration).toHaveBeenCalledWith({
+        connectorId: '123',
+        closureType: 'close-by-user',
+      });
+    });
+  });
+
+  test('fetch case configuration - only setConnector', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure({ setConnector: jest.fn() })
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(result.current).toEqual({
+        loading: false,
+        persistLoading: false,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+
+  test('refetch case configuration', async () => {
+    const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure');
+
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      result.current.refetchCaseConfigure();
+      expect(spyOnGetCaseConfigure).toHaveBeenCalledTimes(2);
+    });
+  });
+
+  test('set isLoading to true when fetching case configuration', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      result.current.refetchCaseConfigure();
+
+      expect(result.current.loading).toBe(true);
+    });
+  });
+
+  test('persist case configuration', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      result.current.persistCaseConfigure(configuration);
+
+      expect(result.current).toEqual({
+        loading: false,
+        persistLoading: true,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+
+  test('save case configuration - postCaseConfigure', async () => {
+    // When there is no version, a configuration is created. Otherwise is updated.
+    const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure');
+    spyOnGetCaseConfigure.mockImplementation(() =>
+      Promise.resolve({
+        ...caseConfigurationCamelCaseResponseMock,
+        version: '',
+      })
+    );
+
+    const spyOnPostCaseConfigure = jest.spyOn(api, 'postCaseConfigure');
+    spyOnPostCaseConfigure.mockImplementation(() =>
+      Promise.resolve({
+        ...caseConfigurationCamelCaseResponseMock,
+        ...configuration,
+      })
+    );
+
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      result.current.persistCaseConfigure(configuration);
+
+      await waitForNextUpdate();
+
+      expect(args.setConnector).toHaveBeenNthCalledWith(2, '456');
+      expect(args.setClosureType).toHaveBeenNthCalledWith(2, 'close-by-pushing');
+      expect(args.setCurrentConfiguration).toHaveBeenNthCalledWith(2, {
+        connectorId: '456',
+        closureType: 'close-by-pushing',
+      });
+    });
+  });
+
+  test('save case configuration - patchCaseConfigure', async () => {
+    const spyOnPatchCaseConfigure = jest.spyOn(api, 'patchCaseConfigure');
+    spyOnPatchCaseConfigure.mockImplementation(() =>
+      Promise.resolve({
+        ...caseConfigurationCamelCaseResponseMock,
+        ...configuration,
+      })
+    );
+
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      result.current.persistCaseConfigure(configuration);
+
+      await waitForNextUpdate();
+
+      expect(args.setConnector).toHaveBeenNthCalledWith(2, '456');
+      expect(args.setClosureType).toHaveBeenNthCalledWith(2, 'close-by-pushing');
+      expect(args.setCurrentConfiguration).toHaveBeenNthCalledWith(2, {
+        connectorId: '456',
+        closureType: 'close-by-pushing',
+      });
+    });
+  });
+
+  test('save case configuration - only setConnector', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure({ setConnector: jest.fn() })
+      );
+
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      result.current.persistCaseConfigure(configuration);
+
+      await waitForNextUpdate();
+
+      expect(result.current).toEqual({
+        loading: false,
+        persistLoading: false,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+
+  test('unhappy path - fetch case configuration', async () => {
+    const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure');
+    spyOnGetCaseConfigure.mockImplementation(() => {
+      throw new Error('Something went wrong');
+    });
+
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      expect(result.current).toEqual({
+        loading: false,
+        persistLoading: false,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+
+  test('unhappy path - persist case configuration', async () => {
+    const spyOnPostCaseConfigure = jest.spyOn(api, 'postCaseConfigure');
+    spyOnPostCaseConfigure.mockImplementation(() => {
+      throw new Error('Something went wrong');
+    });
+
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() =>
+        useCaseConfigure(args)
+      );
+
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      result.current.persistCaseConfigure(configuration);
+
+      await waitForNextUpdate();
+
+      expect(result.current).toEqual({
+        loading: false,
+        persistLoading: false,
+        refetchCaseConfigure: result.current.refetchCaseConfigure,
+        persistCaseConfigure: result.current.persistCaseConfigure,
+      });
+    });
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx
index 19d80bba1e0f8..7f57149d4e56d 100644
--- a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx
@@ -12,7 +12,7 @@ import * as i18n from './translations';
 import { ClosureType } from './types';
 import { CurrentConfiguration } from '../../../pages/case/components/configure_cases/reducer';
 
-interface PersistCaseConfigure {
+export interface PersistCaseConfigure {
   connectorId: string;
   connectorName: string;
   closureType: ClosureType;
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.test.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.test.tsx
new file mode 100644
index 0000000000000..0d6b6acfd9065
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.test.tsx
@@ -0,0 +1,95 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { renderHook, act } from '@testing-library/react-hooks';
+import { useConnectors, ReturnConnectors } from './use_connectors';
+import { connectorsMock } from './mock';
+import * as api from './api';
+
+jest.mock('./api');
+
+describe('useConnectors', () => {
+  beforeEach(() => {
+    jest.clearAllMocks();
+    jest.restoreAllMocks();
+  });
+
+  test('init', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnConnectors>(() =>
+        useConnectors()
+      );
+      await waitForNextUpdate();
+      expect(result.current).toEqual({
+        loading: true,
+        connectors: [],
+        refetchConnectors: result.current.refetchConnectors,
+      });
+    });
+  });
+
+  test('fetch connectors', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnConnectors>(() =>
+        useConnectors()
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(result.current).toEqual({
+        loading: false,
+        connectors: connectorsMock,
+        refetchConnectors: result.current.refetchConnectors,
+      });
+    });
+  });
+
+  test('refetch connectors', async () => {
+    const spyOnfetchConnectors = jest.spyOn(api, 'fetchConnectors');
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnConnectors>(() =>
+        useConnectors()
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      result.current.refetchConnectors();
+      expect(spyOnfetchConnectors).toHaveBeenCalledTimes(2);
+    });
+  });
+
+  test('set isLoading to true when refetching connectors', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnConnectors>(() =>
+        useConnectors()
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      result.current.refetchConnectors();
+
+      expect(result.current.loading).toBe(true);
+    });
+  });
+
+  test('unhappy path', async () => {
+    const spyOnfetchConnectors = jest.spyOn(api, 'fetchConnectors');
+    spyOnfetchConnectors.mockImplementation(() => {
+      throw new Error('Something went wrong');
+    });
+
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<string, ReturnConnectors>(() =>
+        useConnectors()
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+
+      expect(result.current).toEqual({
+        loading: false,
+        connectors: [],
+        refetchConnectors: result.current.refetchConnectors,
+      });
+    });
+  });
+});

From 9fd63a7daad6f3f13585d2d6397402654c278914 Mon Sep 17 00:00:00 2001
From: gchaps <33642766+gchaps@users.noreply.github.com>
Date: Thu, 9 Apr 2020 11:31:19 -0700
Subject: [PATCH 34/78] [DOCS] Adds docs for Painless Lab (#62997)

* [DOCS] Adds docs for Painless Lab

* [DOCS] Incorporated review comments
---
 .../painlesslab/images/painless-lab.png       | Bin 0 -> 220876 bytes
 docs/dev-tools/painlesslab/index.asciidoc     |  17 +++++++++++
 docs/user/dev-tools.asciidoc                  |  28 ++++++++++++++----
 3 files changed, 40 insertions(+), 5 deletions(-)
 create mode 100644 docs/dev-tools/painlesslab/images/painless-lab.png
 create mode 100644 docs/dev-tools/painlesslab/index.asciidoc

diff --git a/docs/dev-tools/painlesslab/images/painless-lab.png b/docs/dev-tools/painlesslab/images/painless-lab.png
new file mode 100644
index 0000000000000000000000000000000000000000..f65257852792e03eae3d2e111da11d81f6df630f
GIT binary patch
literal 220876
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%0DJ;r1F_I
ze3v)*(dN=CXhf_?SW`qLmRq7yr2wJ&gYHaaXsTKi-yIRbH*(x#V+4QOsrxv*Q(+~u
z^CK?Ey2HH7Q;~#;>ThzNd`CPuml!dl>!sA(atu;D;Y)uMj_a*}9%qu$cT%7&G`763
zq`~Bs+#EiC97(9<jir1^r8TjF%S4WUe=mA*#kt2_1PYKD^!m8GRwy$=jb=QgFGkjM
zj%EEcTGCIWJ}WtlwY>L5=D?H0(a6x8bc-o{O2Fmni161TevQcx8Ig~K>EEep|9BjK
zk7WvwCwM5LZjf(Qn))CIDZ5!{=lz?TaeI0M4Hr7^CJM!QlkuO~V-62vV6p|n2)Z8l
zRTU7j+rf$my7z6+)>eIdWFX*n1sMR_s@iXdWo3gI$Sh|{s7j4&Y!GTb%}`zJ%)%jH
zJ%qnw<jIkU_QBzB`1~t8Rbv4Lg*bQlvmuQJi6Ftjp`Q_ZXmPPf?OK0mu)WfBR4E+o
z&27gU(K){(QHd?!i1rHz0Bzk(>gPjRuLqnhwJhXA=8klErF1E;sl<xg$dc&Vyoebv
zicB`8BxC5gxR}fgzl5D6exx!s1{RvPU$5qFhcLx7nw%KWVbA#26GJx9F^Y|&vT~HZ
zfIO+b3$l~!wHFurB&>93&32n{nl*Inz1mODRz-k<@zWeDV+!Yso8yGv<dfQJj8FPv
zGDQO0knsls8>^BK@0N~TLsWi~paty)5mLq(c2*ySS?TT5<(BJ6HOlce=n=mWgl&Dg
zL58MWL2+_cRw<27v1D;*v?{w=k|BA3%mI}hsL|KwyXZLr;-N4Q6p{C?d-R!r)VbH5
z^2L)xEwecIoxQ|!{!By@x6I;e-w{k5(Zk(k*PtSL|Hrz_K;&I&qL&l+5a`rlUvl#4
ztAN&n>q$vYgI8O7U@2B*Xu##)Z~I@Lq&mu%m6DSU{sFG1-D`OkC8v2cb=T?i?~%V*
z_U98EC`@)hS>N^Dyc{!3=4X@>w@lW*?(oSMTO=3=CyW3_;NB$LSj7ez5SQj&-Vo*v
zXDM~*L<w4~NJ>RK6&V@XwM(VqhtNLVOg4)ox7toQ-E*72;N!nse>zx#`Gheu5A(~*
z^*BlajRX!Z+fO0Sk4`KENvzVR-L2oU9UB@!wmK_r+;Wx9N%)O|iYqW}1r|&`hl0(E
zk=nazqdthKY5kEdTSNQglF{_qe((OBQ?SighB8kTRd>PZ0=B+qsQ27eZ(pgm1@4lL
z=a>%MBJO+&n^j2eK!mzPOjqRx57&XU3a>>q(xo)?pFc4(NpYcRr`QJ<dy$cmqb9~`
zc6~Am+{wv%s%(}$7at-QM$La35Z$bc-;5>+@47RMjqO=p<&U!i0c%7A@~6Z2r#OM~
z%S}Dc+aKx{cwv)Q@@S6a0s6RCHtddX{d=Ar7;FUSj(*tTW|_&Hw8CMfN!N4LFOb%3
zKA<jJu7VR}x`$T&>5kI4$cE9l$S31*sK4dKUN`#qsU_vMOF`?#e)G<LR|yU4z6nS0
z;kq7PV1(vT-%~fjXmC(Toz3Pa6gCq@32FiBXi%6B`}<fon$)l!M_b$OW_!x<jEXYu
zV?o`Yla=F-`;v|{%0(vcw^ue3GnmtLZaUJ_Z{L2-4vXi92^bzcqx2e-lxc&-rL;1O
zT`BYR<=4aGgadBNH~YU>JUB$HQqEj{?T}xsXTuzKXYkv8vg*N)8t?I1)I9w`YVS5O
zUcFAua@hXVdm!K0Rp(r=v#@~-O(O&WukaZXBkS3p{}d|yyepCJU;pTN$|bVQguAQK
zQj`{3*HWh|B_*t6H`E6D1_o*z4_@Z$J;%QxWo9O(pZy>r@e!Rp@}q8xfb`vbzP&iZ
z{Vpfy$3w{=%J}r_QSp0=6}5GT3yn;^>g<@~oTJ(q)JTpsFuH#Mivk^ej(np3j0u!k
z?lUimmt#{?2&`g$)|N{=I?yhc2jTSSeDJWa3J^@m#2Q!@^G&<Xy3tblFi1Ov1=dkF
zo}2rNH5#c<Ri<pqfEYF2JyoUqOpYn3AlFv*BPVyEc#SpRTjn`{rIauiV--8&tymqq
zQtDGl5Jn|gG;e7UY&2VOU(@JTLVY!1%ZI8owKn+iLT4EpND94WkjSRo27B~RXWV{R
zci0xSsMkJS<qvz^*uB7dYEjAW|Kg;aTkCauqaII%&^y%Q)8eX1h5q#Fk|1d>GI)<p
zHfEx+H*o1Q^Ok#%%d*D{XB5u*kI7KYjn;bRzr+h}zqJhA57y|84XTU}I-g<16_+?y
zW>`RVej2eiIhxIrjKV`|wOz-m|F%47YFhZQ_~7BaHE+UJY}Rf@I}E4<6}up+t8>4(
zC!B9oox9nbJDa94)x5S^FJLsSX>M&T-oBdE4p^O;`>7C$o-m|vlvOkSToX!ZYcE0Y
zSDg(pv^+EOMKZ<A;C2ku@FqWfZoGCKtao7R$*$fo`>5#er{Y3uCDmqobuii(OMg8W
zo%*Cdk#Y)6Qzz+<XGMe5V01fjcASsCWh4h9OXxXjm8(e=1Ju><seaW#W$&|)lT|Bc
z^{iO?C#`#5yiR9h6<(dOQL&&(eSi1*-M+r!+ViCw6S<)^BjWM2oQ`)7UHs%Hqiva0
zt`As)=a9ykUOJhL9Y<kp4_JAH`d>;bW!3Z#6PiE4pzKACZ@Guw*bBY}-D$s``JO%O
zr5U+7iAwxpZnB&v-&1LIqC_~|oeV_o)D@H!U3?Txy1hi?yZ^?Ib2cu1vTrj&5?VT>
z-ew9PfSuu1^0i0)(X+!sV4XVCRZ;b7OdEarzR~%oExn$LBfRSsVZrca$YI3vbWDGP
zL+-s4OuVB<w7TX8X-MvIK6Tay|GM&2n9G~(45iTCp(67oj-&i-TirQ1Q=jP;HhVov
zob$z6`L%NAcO}H;HnZoA(iLY~i`t{%47R@}AC7*Omuiv7ZMhO%NevbCY-iBo#?yN5
z@g93hEJLS1!PNeI`(ga(_AGyYDxJ+VYlQr)^C*<}v$jnqwqZ8ouih*DwF3OW6_tDQ
zFqd~_OsVi$BlZ;bgkFz7U~r!H@UL$dZs^+OkBOQNXH!Y+c{;f_RogDc9NO;mhSFMD
zXS~DGrfu>cVY9~Kc{u)fay#^Hrs-7Gch9yC#Osii^-mIAqNT@0Kgeksy9{56KeGJl
zdT?IP7SB)<+lWM~+0EGG75^FH72!f88nC3eiUJ3|R*{02S+3(lcXCI{yX7@k`nzob
zm$|%kz2BesjA@28xRc@6TPj{P-DL#M5Wh_LKa9O~SeEJYJ}d}GBa+ggfONNnl+sFf
zcXvK?NTW!nfOL1KG|~+Z-Q69(n{{1rzx#QQ_rK?G**mWLx@OKf=bRZjB}+5s$iuVE
z&Enn*s<bjYmC7XVkzK#?#%!nZmDeXz-z$sOGv`K}p8uffx4hVCTT5<NOCxOVDCO-y
z=nr}Ij&&#_yZ>>l#YHiB(y#(u|79YnNS4m?`kU1eqs#u+7vc%~Q{`vD4No2J%^fol
z1eh)TbT>rc>eOsBvWHNh=Pq6`Nl-yDgKVnQg^s}K93n=h!1XnE24EC5vprand233d
z+*XyQL{>8&LE{v7s1=(l#=>|zxi~CNwjo$5WEMD5RuHDf$EZVXH2K<`>rRtVPgLR(
z&e&t^Zp=ss<c<fbib{I>*T%#9biK`sn^}I$N%Q(K#O<ntk#r=8%kh|-Q;<2ooAO72
zn6RxVk$~`c6dPNlywc-$z|{5A1HaM;89k+*^d7^>nFQ4srVkb3{CpC0sPlUo3!L3+
zOt#c%GBO`N3<9O?@ca!xP9j~Sk1x%`1K!AQlW{E}SYBL0LSU&qgl5;G%S$$Tq{VC{
z6PrHMOvg$5IW`sPnqFLFdisk_*WO)obBvPiBRvBP6u8Bx*=0^zwHhb|1%))5y{JBm
zT{pcOhDrjJwTKNocm()S5bYe6lSQ|Sc+&Xc-t?hU4`B~?C!?2~Fn9D^p3_}qVJ<74
zhN!5#Oze3qhg=8;i1pNo=*~~I=1bnHBdrD19d*xIP*smC!wdzV=O&h7l_fFcV<agI
zot%>ibx`+<o+|~nLj-s$O5(Q7x$zR4qn?qurzp!|x@p3^9~WBvGyxsy`gkD<G68q6
zIk-l9d8ab&g;J3wYK8gD<HXwUnp<N#IopRTR0k&t$&t_bG)tb5eE^)@08z@xQAb=q
zHxgJE6<#_88NRAk8Iz65J;2J!$})!8Xej*<Zk0fU%?$a%>+l*>yMO3GY-z^~CRPv;
zxi;vMaxCb7gu%^PiLY}}Vq-10FTDy3deQYL<}6E!u2u$vyJ<Ny%4x-V)Wo|4HJi$z
z3#e%<B;2f`JW`1*WQ-!qH+FXmHlnR#dt}*o4fM>uNJR_XA*zX7xcY^zP~EAkCm9nA
z9&SiVO70&rC&=>@R(Cu@KRiAj7}2N}ezmo2dU<1Hu3>v2{(Suq+c~mYp-nOY(d;nN
zHFm4wI-@r9(6jXLg8Fqq9&gl`LGJb9#^MLYev1p9FLi9?uXzt=z9e@jDKxSGxC6g@
zLyiZnn~n^qX9xxXId9^_24-EVGqKqxhyEz$fK~qi3-nu79Nt4CCZ<8Om%jCgjryc>
zvS)GuEd;Y=@s@lACGJN&n~aQ&*>nXOz!&qInmPb|+awwbJQz?22?;w*MS%fqO<fTO
z`zHs@MGFEWUUi4H7;N|cW%T9G?@+f{gE=M!0Y5?uK`yf8=KoGy+-KAVM(pYNxPP)&
zSS~J4;t@+t2eN!2XU@>ti?HQLMqtPM0bF99h4aRp>`beGWJo9}A)%o!s&tlNfj-S~
zlo>-_-tjt39&T?X#Q1e}*-1!La#7pcZ;8~5e0%S&(j*R%pUgYvx*9vlqMvqu=0Ws|
zh<3vQy%*Oiu4gBvow?>z?vl|8(R~VkfF%#eb|@e*@8fjj_8nJ-EJbXsFNWc$vAqNU
z`MYJ$tE|rH>lodr_4{w}fB-iy+@JjZsb&2=#`+0Oc#d+GI2FmEDWvb9^5V!+xkVTP
z52k!7_b1ZM(oCWyDJKW24_C?vrmf>(^FalH))fh4sg#%fod3KzpV_mltzki+qT;bl
zV|?N2APe(NFvHgMwX1mYSCs^o?~1J6YimDLJU~~cK&8i&W=(Mf9NZec$(TPZ5(0}0
z(j%p%uVQQ1W#;&Pot>~{0l|WN9*xCh-3cfNX1?mhuLsMF&;$j21Tg6%vz>b<Hv_{|
zgIGZMd;MX%>LwuljWjgoYf-{hT5I{OwJ?@sr=fx|1GS#D(%sGSitLk%!SWsjcxFLQ
zWd;dBqjPcsm#176`JQ!~tO9GcMy}ufMw~yvXCB%|z^koL$pd=H;nYCgPXph?6tvHh
zK$wvcy#N~f9#_6aL+fzatCXi!iF%N^_=A=TVz)0*N7fB)Q&_lywboQn(Bwut0f-%x
z%Y=p04p0$IE|uq!3Bj$YC$ZncBnS4XK!~-SN<TmKyISRBJDTMFn%wcJjIlM5aaxU6
zd=O@k_H8B0R`_7rmzm81n3Gmke)aWg`1SBTwV?fVr(A{1iaNQdUsxFcNHUrLK>^gZ
zl$|eXyPUj|5q8UuO1}1blOX!G`0}iLd*+()1eYru+TYsRdX%KG{Scdrj$crzYIJ6>
zq{jL1@NlHOTRSz%{8?F4o9<SNe6(xXY57-fUgcz^%NV!Jp^maJnh)hXTSE%@$^FXH
zWvds(zBJS6d}dEA9qdYSaPRF^Sq=>5y{GzpAWSKVJXKLp93(&k%6*fQN-{1VvI?NQ
zz7^VaiI`~Mb|0nPugFFvCrJEif<$hslom94d68ExVUk3sGEpJ{KY|5uMAn-_r_i${
z4T;NU*4(p1{@(j{l<**60Dc<sK_bH7R!ttBG~m~s>9oW%F|7K+RfRidix(`BOX;lo
zYh;xn#aBkZ%SCwd+C|lW$9?;|r?>ys8;41ee;ufQ0+AGWC~QPlk18DnyoT5_v^QSy
zIU_^El$jcRO~)v!O<=Ivk9>Jq*|QAQsA@1ll?8gk`61V1g?^cTuJGqWrtpE#HR&gs
z)ItIgJFYB3I`Y|&3&JT8#_A6)gB%Y(y|=W^sg<Dxx+bAET3kG4)N;8nTU@TR>Ia1p
zGaP7NydaSI*9HGsaywa%X3fWJeH|SL1;X;e_O`Zy9*u>bAMCbdOEX@kCG{su<qaIj
z92i(0PrO@RiLdms^M!Zx`d`bLWd~{JU}%z`mZyRb54*2`-{ANP?nityl%Jh~<=#5i
zr_Z0^H3$j8uNv-s+3(Hx;HRCcNAo<V+v9S3UJec+3?z6{*{^}bY>0W5p?{g6hY{be
zYk1bsG#Qa>p56@4T>03n$xf0<cu|fVoPA20sJ202WGbahKY)6;%N}ev3TZZI;A>gW
z(Z2jf^om37TX!zrRz=xyPnF{<C7K5N3v0hAItq$`m*WBBpey7Q1yi<(X$4oP+p`S?
z?4w@A@5wwe<ORNo>Hn-Lde$A}oGTX!Afw5>!|JBG|1Xa`lAT-;@1er8d1h2$U2@69
zZ&DY!eX8Ym2feR0?M~NhtS)<<${UTrd*R7g$xi6`t;(A{BdhpI*yhb)ybFl{^v-nE
zc-ce~Us<W}uTPpH3=I!Vahsp_sCQW!XaK2<+FMyMY;SKHml2u<0}IV30lUvsNcLqC
z1{$a0k$1E3ZX@l!35C;4kkoTdHG@90sWJ>2l?uK!$w7?Egv1E%svCcLM`?E-D7M1z
zKC}m)2R-W*#KkE%YY;{Iyok87udiLh9lyE7H)t?lMF9wR#^N?%roRGjEKLe|-J6T5
z&-%s_hOSA|^06z_ivcQLzl!B_T|`1w>@XhJ<gdC(_de^_>E{c9=RVuUHU*zPxxL(?
z&_!L2H^=dd3B`EAGGdrHferknr}49S19g_>5@mR4K00Zu7DdoA2b@&Cw{Ph)#Bsu+
zXasN;SB~NUd-&^c8h`RgOC!BJ-9ggOAQTi5N=YFibO^@t+}|Hi9uc$my<eTt`_(bV
zQ$hgzr!sILhIz#QH1Vbsmh<z(z42$HvoVYiYMc)3!LfJcS{4(`_s_J60X);mWr;n!
z^dn9B7%7O~uk;9dv#6<Jhiku&YuIW97@}T4!ploIJR2VXEVq)ZBx8Sk<)b;btNON;
zXV3byy1!Hc+d!$bry|7ITZw5-NK;dX`}VxG%HSBR9~~Kd0v0J4jB}ZM>iYfd7Lyp^
zum#(tY<*aHveSRN1Vk7Un^L1}WK;>WDIQ!P0Qj}mS+60jtezCPwi)Z{>MD<9=jEAF
ztJORM>YGZl5_HuYwMfVE)GVwx;2;bC@mU)2yE7cZD;85_a3rKE@oMsnV-AGX!X~?V
z0{f_>`Tf)&@ka2v%n8q!+o}<0tlX7nt3cf(UOAait@hq!mcdP6U}0gIP#Ir+i2gi0
zzpx9VfMqZ-Jw4eVu>D}o_!7~6!s*8}yAGy>Kridg!qLMB4e5_EaIcC^QO+l;FZ4Fq
z?4@O8eG(E>9UZH1d$f=1pisdxs#+Enlh~i?>bULlX=!PNw^*Zy_)X~Oq;$IE+#0@~
z8`ei7wTb*(xp$Yc$zdCDA(_UYv2Vh^d=vw16FU5e1%!hFc`hwIEiH1W{Ag1PD;fm_
zg~xSUIPO0yn8MeJ2^3vK@fBqm(X4H6=RL0{d)z$K<+qr2qRxs=_;Wo*H)KFO878br
zIVVcdIOT3UCT7ENYaLaOWPp9s4MmL$DXnCN^g>P8Rkg2Eu)z1IMDAt3*b-T)N<Y8j
zR^oFxC7P|&-=FPIi@BNo$Uh3Fs`%M9xO(kT6tzZB`m(Gz_8DRv6pK7Z7(TCW7|#{5
zLcwzO(wJ7h<y;mjtSO#mO2#G^%hFA@v0J5k=mlGn<2FCDv25v%!dzsr{;yN>YoGkO
zVG1V{JL81MW~iFgx&EvaEF7&;mV{SpO@2`pEU7t8u#rVwaKKWskf<?b6tzmGSi#_U
z7VD>+`rf=e9JA<<_rEOlKgaU#8`w#uC=0^?BMu;vLANxl=2NN39(C@GvyRt;SHx70
z#!qP|8S(ZSSqL^Zo=@O9REaxG3;OW8=^h;)^HpwfYJvS|^bSWxJbMdCRovY8C0M%b
z|NZE{ZtclQDZN7K?XWlbB({bR^4lEfH7)?^n#l<p!pI~bt@a*E<zyon*G7hgVX6L5
zeSWc@>`q!HS0q9EPTtLYFqPx>Tqj!j$0S*zX4*r8_-l#o@57h)G;2t+C>YkwXy%2u
zBZykv)h*Z!-BMTAgr#uDWlyqwBAWco;i$hExILfU<`i<bev36;tq(Usz0E=_YH1ZU
zt@tKPjdkk@?w_#e!Alue@<qaU^Tr<`nb%ms0uz07_j6XRvuZ_v>z<h1H8&Pn9>8-S
z>{BqCFI$xMTrB49&9ANbXIs<-h7RtSj-jxM|NATadYut-Pf8>hi-|I5wmJ6i%NPzj
z&%A-|`*FQ8(`aFdA3L`D*R+m#&G|D!D-fDiSJrfvGV&b{5BvvSk>Tv_?v^Kp-aNGD
zf9zY+7t-IF=X-mpJHI@w*|AlI&&bz+b{aKf<YXr$m2prs(V+Y3fKQ~<R}?FN7Vg?(
zA{wbCYseo>@dLjHz1!@-#QK~ZT^M(AbXG2OWE$}hKw!cxudFP9jhMnCB6Qw!=oj#K
zqLE832GMQZva#h#ePoG$Hh-ie+QDiBG=guRvcokUW>*1h(x%V-V(JaDEAdHIJjUu<
z7^5>-l2s0Lj?|gdZJ5uH@EUP5yX^<~zWu?>xg1(IMg!Vq#fnyUe4+R6QSJ9$f9$ew
zPq}+VO`Uhp6A;FmHg&wepLI|%N%Y%LJc91Upa6`~`}YiZcz8volav5}*tqkHnMPWr
zdYN){7oC?!y**j4@U0WHC=6i(b$%U_CR^%cd$znC3zfj5_Ka%YrAB`bLM4q)4b?KQ
zJ9O4{SQ?OP2ts@9-Q7~Ta$OP&vKh&*R-tYWHoEWSm{urnUOKL#d!HZ^4B#H>Z0(!`
z$P{a@a31drqlG}4vKbWT<4^GXenP$-tn;hAv>5IcvtR<d%+2j~iAJ5<YiMj<b7~Tj
z0#Iqusm8mTjfGU9pkli%!u6S#Fc;9!F<g63s5Kg%X}F)n!cUDSQ>{eG`aeoe-jpsc
z=z~L>^T^E1ywr(LOvKmkyL|dQnh6-w<+w$uZv@a5vvBO<am+>^<kaL$`_0)S?Vf*o
z-2A~IJQK^=-!J#5HC4xQdfroRNY`GHHX$)#etrGXMUlx{74Z&a$K{19%PpE#+?jH=
z^s8QzU!FSU5*nG12a#qD82)RdRb;~m$x1`|#1ldtX86bJSPf}i^D*V*{>e!=w}uAA
zQvKJos&56Ytr`6gp9kCTOtpZ)`D15|JoW<}9ZwjaI(7|VusbmlH1P0Xv%12*5l~^k
zRwcA>#Lz%XPNsy(_u2$vi#MXiIG8k-&>~?3B3JhB*XJ7PfN))be<u$B$XPUylA*}*
zb}tziP~~oK@`kftz3u<ee8`KEgW5bK5KHnVbfqqR+?T^U|8u@)3k1aN{^4PsXVk<W
zKs66-|MavyoY-4hIy@{Z3-<inaVhjuCBIwdiass`+*2g%0hDZ`S095BMFe$C09*wH
zFfSDwPgU||AYI*z=XL@^cRhe(KUih;==!>j!E*j&eK1XBXN$r`5CVQeHKp6D`Cje~
zn5FrQ3jCryUxg9XW~sa5$2byr2u_jJ-oQiN9c^Hlxh-t}ah@rpZ6J@_6+dn#nD)kT
zAa#T$HUSoFRCUR;E5(C))nRF0%Te!Iu{Y_4Bb1QWh@MdDLsR&pWI_ST3a;qb*nohD
zx$mX@!Odx5+&=FjGD+CZ0(UsSN4?_nRHl-CIV|`E%8OikMyx-#akrL}GdpFk6|8+Q
z<Ut&+00-IQG&!4i>h5@5{3K7<sB>6QF{A_jfr<RWr<P2nJ$;HFa|L#_-5SFP4PB*!
z`<x8;dnO)f7#d|C#bf5)_{x3ry1idofJaxrG#_#CvdNY75Lz`(VhRe__wUV~4m02s
z6cp%3R%R61wTTejgS4?c6jU6{9AT+=-^YBpQi_ID$ALQm84~eCBqVr)_*1d<Rmo$l
zD{*DqykqBz!}<b_Ze^GI7pNS=DiS=reSLj~XwL&CCU#*_Py{UB(zmoI$L?xo%L2ju
z2j8)?GWp~W;8j{^oCLo77_v85ux@+cu8+aXizrCDua==7L~;|dM6|n)q6!tw4rEQ0
zlqMBxY+u^%O&VC;jay87WHA|6k?k8F7im;f?Fhvu>R2@&J1#Fc|Jb&{WKe7m7XF?b
z$QCWUGQ3F|bhfc8kUU$A`2zz8q&JG9);e$qO{Pp?`@`f3d3Z?-oO3tUL~bc4wqA7+
z!mPYD>&iGe5}6vfOd8wN>9S*>1JM5arh+QPD5QY~q&h7qeRpPXDxc-qL^CiEB;-`M
zFsklL0t|`+TU8Bv>uiG-4Uqv00o4P?DGiB$MJuSOnbL++Tz?5v<~7RqNV)M7OTJ7`
z5fB_^+=wF3U0aQpO9zes2S@e(z9qnTZiqh{u(7dWabeCXFa?Om8hHR+g0qd?N2kVX
zR!O&V4V7>ObHiBJBu(PS0A2!ARxv4^M3~Rx>L!jbv3S7%CLPYU+qluY6paz}yri1n
zH3rYz0<;AEor|t89ure3H9Qn<wqNFhXad+|NRX$er*V+YLtmmEm3)aPBppA_C@-}8
zAtFXJ5$9s`12p0+mFEO}aznGydpZOJm~+gcwj-Sykqnuwp{t(bNcu=fbo!T?cJzvr
z(VrTSj3Q780eoX=XZM~LX=BPM|Cc}hcdW|?Mla&TR>c^8J;KTfce*=c^GGbJQ0Rj-
zC0VcwjD#0Xu6YtC2y^dl4zF|kwXVrzDhENGK{`);g&M+@!2k04(tJ?cUDEG0I||rc
znfAziprU(^$eOjlt6NJU2DcZF^y{y1W*u*Y01vwq{msO#>tFoWgM&vQO$D7t@LZLu
zu)AAQNXT#Lrm{UZo9MJ1pH?Ow%6mnm;*q<7U>S1TZvB()<%I{J|4-Y(=Q%~zq*>(2
zwYaqOtuKSLmCv{<`y{?%;dt_BqS}R5c$V|KArINV*XQ>|vXB5?$D|H{%YLt;`Y6EC
z%3jzo_i0FZ(R~p4-wWXxhdQ6ojFYJ0w(zdkb&bW=kPvX_@wvsAnEw;hP)IWY_fc6e
zwXg`295nkB8JWL|Rgp@G`O7K&0-wKcDV=}MI4#tF`Qinj^+?J>YwGFdR+0VjPfMLW
zJ*|^I2#Uq}q%SD8cXo`@$&wzzK)#!26Gc``V+GTi2SQzY1ACJ3p1`odpq>&BBTtKl
zM1N9|(AYj*q7z_B;`w5a1!B6ao2W^A<ajS03r)(&>mO^G8GEuTJ4W@<*RBOKQ5+P~
z8uv_<H90^>0I|Z2{I|dHO;Ggb{bq8FrHkmf?<#xlh+JG;+&AAro1<^#xFvqS3!kSm
zv9zLMR>9I=Km{bc1DrqwXS2_lSy|YC;6bs%G!jSry%DiKy%?W^)P3GcSicK$Vs!>h
zt@>}!Q?4h;(UnDIVid2h_LONf%VSqv889r7OGh$kl|8yTH7?p4^~-Ce@8rooq^QIH
zgbix-CEE$A>|7kpgM(kYy^Gn9a6Jxr7heRmA>q$p0oC5^G_6mx`5F}g46LC5H)-)t
zTr)8L7fL`uK?%Zt^F|q)nv}o4EEo?8#__p0+nKH#|EFpt6Y9Awv<%ITP_@q9UO{_%
zWc%%zkkQ=nukLpZWLNuVb0P=ZHaZK7i@|2o_9;R=PsKr7YJk`i69VE|ZR$l*z;`b%
z$Y7isB1T3=D@q>q*Bx{2ccioix+!MUtYo5qt-B5G=edF}dc3$KwRE_GDDGkbBOF{c
zsarG~$0}j}F@O~nFs`ddIuX-)CGYdkJ}38+DaF3^R3@KaUe}aMeujqDtXTx}CKj`$
z6^tY)8HyuX3j2Fw1LQhD7hcz*PE?_O_%K{#I7r9te9S&o8T7$(etv$HjLOR1-YdC~
zZY)nJ3<2xer-X!HVgZ<3&7#`c_^uLhX4?DEdi6*A!XBwevDvgFi!v8$1(&n!9*ny?
z?-De``T02?j2)d)4J5f#d+T_|lU6?zenUel7O!bVEt4r`dGh{gNxm(Yxc;!6-Pq!&
z@>wxA9$d5)C-@Ob&m347o4AitP8O3?|9lnTNRDuNuCF7nV}l7oaGx~w_v1c(q7IBf
zsF9nJ0$Sf9K4*jl5+ff213kjR*mkj<a7CaMC=EEhe{(x4lnp<59qD0ch_{d2|Hzu?
z0Av-=+>KFb3|L_KUcq=+Ly*+bMRC^-<7C#DOIN=^M4os$Up>IHR;ka*tE2y3%}3BV
z>U<ggG3*x-+*iHW+?SmKG0aYs);5JPqXXB3m?T`}xTX4%t;IUz`_rHG^doi1h9Lok
zNK2g)?_vlrW$T*_P@i_8F$^vGty|lT4VlnSp*^f^dop?H{2=1nhmbwx;fw?2SZxFd
zli6WcH&d&Q;7X$(_j}$-AwxQa2i`L7<E5j5lf(nJppP(eVnhPW%l53E`yo<ku11{3
z`U8A;bi@E^e?sXJgh{NAVPkJE9N+o2Qx<ArK?@ccPFPWqs<c}aSFOhO4bW31HFb(8
zLx)*aP3;F|?zh64K$9Vn@zpvfgnMby_wRyRlCdXo;g-my`k;>kMba$JQweV%Zg1Cz
zIAHQs{D~PE-+&2i*0hlS$hVNz2yjIlL2q5^NW^~-k+@vH%q#zKd3&vR1Z?Ltmzv<l
zvE?J3AN6IcN0V^?)*)P46#vS1g9VVHCwBx#@DE+B=7+!WO+F?nQ*5!Sw!A!R6s=kS
z*yS`*i~&T!ZvdDj49DGJt})xy57~^7{6HGTE<>jS+1S|oLl>Dt`KcUbz7e63&5d7(
zVyS(7mkHw+$KPofq?fqd<nE8w0aEMRJ83q?lJ66mtJdTzZk?b{61(5Ly`6%F6o)g)
z<RW-##KxxdLGEtfMgH2<yBmzR%ESF(V}QF~D^&$aG&TkYF#%K}y~s}(lodbyZJD_|
zJU%yw2{7cFt3pNN5568N#y<p?z`qHu^{0bn;x*r%03??_#wX}{Ap5eguwX8KI~4n(
zb8~goc+7BMXvMU+u)MHhzpJN5rr#?lD5y>L`SVyHfGDd{Rio5IAj~&AyvPPgMUA<<
zQb;|y`BpBW!p&PzrBktA+-7&5C4m7Lu3?)ig|UvRD)yMW*CpM?I-CzTJ%#krFQD_D
z24Wefu_+hHcqf;}b$M$_x$=?#786V5+|VonSOxOx%WlA@43XyV(dC;>EnZ~vI4!YE
zw{$pK#JmBLhGb39%amw2k2ieVgcPk^c^QwaX*SJ7%`xSZI6u<BiO^6gM8pD^H5h|x
zJS!R4mkb~4tFmANsG^D2dY^lvzj8MfaZb?FsAN_|mHHovgB19C7T@EQ#@=+X3olt6
z2bzw0j0ZwMG~zNOCXM>np|c%cQ~LT0$yE$Y?cL;QE1s>ANeT0J?7(Q&-nPI9|01fv
zYmTm7^OQiwBz7x!F8l4~Ewnjdel31q<?%f5N8cc~Y|92tDReCK`FR97BD-;9?;m(~
z`;F{ZH{9Mv-0vQ^#fLvt;OMbU`P?3YD}6)d6`M7*gR4_D7}4<%8QlKskcwLg2Ad|Z
zV?ocn^7MuXVKw2|oI~Z{Ek3UsU`(c1u`SAM#2+B$hd=pfo&m@O##~rdmwndVgnMY1
zsfevWJLSDst4+ftghMd4pA&)`i?qN=@>B$N7|K~eYh()~#t02q+nk?=XQCAIiY`%z
zArKWzfql2ZiXM7;YRnlRB;r82w@ESWuizR$<X}-ZycaqohYfb$4luCl=v3M7DeNhB
zk-{^t*TYtKx1-i=IhW$S!fB*Y@|&S@0y5b7j+faTBZ1$cp`p+B)B20FhWFmSt@1D*
zw`=hytSiL4nJ!vzFr6)t7$pv&1zd?pXi`&9e;C8mlXpPT%F~R76CT<Z>arKR1UE&_
zi8o#1=NFf8)F!##XJ)7zmy0tO_V&V1cw_W)&5P6?I+A}tp(hOGJ%+^H`-LGXiw@3s
zM=pRqKNHm0*Mkj6hTE&YTqL!NJpwA-$48AW;|tOsAPIH{aDfTK=Zo`uiumrZtpaI-
zbT6LmK*r^07B}W{?V4aAD2N;>kZ?P1v(Lt|BB1cl<Mdx|!Qs7jRxQ7oT$|JUQG*o2
zu2rWTav74nm!@OuqB_?Y7Psec5h!=Q-#EOmvEgYpt?LXOdpC}36g`Ye=x(+P9vQJs
zcpWdj>WqjlC|uTlwO1bi<mLqz+r%6fjQ1y|bC+kIQ<AQ|AmTc1{{$1k8*>6ws@l`X
z$X})>dOx0$1U+d;<c#FWpF?q3d^b^By%A=|CDbOw?!5it`sTA;=DFy@UHN;#JaNzf
zu<&N{xaYYdFl(}%=dQ~4WiD+k^>tLDJG9g>cBthXA4~UH8ffbTX}i`Dr&-;t^Hrz9
z8YH;BcymMx0})s(-|H%N&X(ymB&~*!la*d@^+kr3<MP)l+0)aV)R8SOLU-XiH&A%I
zO36pHj`a$~3fD+@m}vEL8VdTSq!x{BGa13FHg<OWZ!K-kFE5F>$VGN=f2dOO%X1_i
zHKK?nR#!}OS51~bMss<FXl{SCBWwe8ykkKBW3mhG&P@wZ6|9PsarEL3^Yt6$=g0sl
z9Rxe9n>t8-&k)NMQG!rBu58g{33eb~6xZ56-qA8urWd_IsEcs&3U0aL6k$Z+i`&a5
zLTzoG-TkenN8}?;Y$68dRkCW2N?a;wFHd#JNlDQrC#&CziM7hJY+~&L$s`v<yaAM2
z`@PoJXRnbR92B^(=j$EUn_ap`-pf3(w+CQLW%DW?e(u>0(Med%blnC!qJ22|Lx1=C
zi77OF`O1YF0ojOObToO5eE@%SAHLOah`?wu1}Gmx=m-JfQ<VMlyQ^y#kh^^09HfJT
z1L8JeF0Vo&*C#jroJ$*}4cOCTp*O-g4IFf9pHnQxQ=*LHU_oy%b~`~d_3!2tDtPL3
ztj2lGsS?vq^^8BhifGrF>FL)2CJ#Fv<!`KmbDxlqv@9%c2L}h63|l2I&<pvb$#m(&
zIlM$+tf}bLH}FqQO=Zj!$M0lDWdn0|Yer2HN&!*?zf3oJMZVT|aDhDu!{CCgysykb
z|D4D_cOYM_NBwDPWVCACI@b*QH4GkyH6E$(Y!DKzdtse4O_$ZHSJ3aeUh>O30c32F
zt1fy*<4xeDlf@>x-R{EGZeB585%WavFcy%bIX~!6d|UrHBspwH<|h2E6R(-3{_(y`
z3j>}cPi7yXME$*+IdRHy?wFlL1`t^Aw;qLsiG$CBos1|&P&|4OZL@tEZ+&Xxae;<x
zg?%fkiIS-RR%f?5WR^@|_l+Q5Dz;i$g$E;;&m!Ks%^L46075l%Ow7%rvH;VN*DfgY
zKn9fJHNG#8Ks7!an}R90ZfIUAx{qPSTH$6vM(Pe%=k_Eyr!a=)ANS>ngZ_6gC+$sB
zlD+wi-D>d#AOwit%t<;Kvw`5@Jz0b4N!|Y$<Rx6%ysvu(=zUW7$^pI_Dw~>!b>SqM
z{wi%FT&TSvxv^7I#CW<ZK*nGpO{!52d<mqMJFU#7bQh}d1IQWlPaNL%{h%H$zq7@K
zM<F+;D>j1@rn^8#tDtT_C=&ykYuRW%sfBM#cHez<es!UJTpyMOWT2{!cKweLTJgEh
z$<6C`2#yII(FmM%5qE3X2#u{cveWf~o+1*A5IW2qQ4l!WB2HCWD10>sKv^C0sgvtn
zD+%yFAh6ywNF--Y+o@TqjbqP%`dilrP3S*=rqoFI(ba|O=a!zhIb&@tx+)XZ#QK-A
z>MxumjRkG%{)N|t45;IcriP@Rb6%7`gR(tiq@qG_vEP%!YI0FJ+fB=N?p^DUKa`s*
zsN2)ijP&+?97Ut@4b!LaQeKf1V5Q=rwgYoFG+blJv^y$T^a|uwqw4oO$q!nNq_T;u
zVg-?&{7yu6u8;UttY9va?ua7CIbtKz>aVWkd}=N6NC<vW5FjDE+fCvU0tqSGBsZQR
z-X9(p2MmsE-z0nvb^@CiE92DF*CA$X9FClfCvu%>_A==(+^($U>Y~=y>^9&2&Dt3U
zHMRI6pkh0kA;H*OVNB;r#pWHFlwU7np)bn5fd_PyG!f<-{PyNu+D%bWxqa7#4XkiU
zNlBE7MDA}LtgYX)1F>QZeFJB_9(a_fNVA#56ny!F(;=W4m^d?7s6qHQ9j{b>n^=cK
zfvX$o>bBW$cDGeX`Zu>vp3#3!rw+2CUhUWLI9O^YAxX8nsg_oUgWe4As5PnHkfEsq
zTDh?Q6=r|-T{)h7IZu@aVl$uh^7g;|u%=RO`c<8YkqLFWG@hq$8~Dpy4xf(D_$)6i
zYttW5i4nQ0;dZvRe0E`*Wf{q%a$|$D5J`Qs!nqFimOf!YxOh9cc8?rmPgmSw>$qPp
z%u82DC~->&2TtQ|1jXm(4wf+@jVyRCkxRCWjzWiVyArxL7qp&zQu`})?RiOVdA_ez
zexCnL0rT01Ll=t+YsMDJpDh1M1T|+L9lg66R1jqaiH+ux@Y{D1t*Jtd^Xr34hI6#=
zH&<uCm~0y=W4-q(0FVB61p7u}9N@XUwOaj&n9DHS70TO?vUTpkvkqIYphIF};{4iH
z5R1v!Qj4$P3vzOu&hTc#@dBC|Fj)MH?lV9yfB@+Jp5(?!h>HtOeoXY+94k-`287x0
zsQIn*I;$Pn42L{&J&7pK)zhgMOIQl_#&L1kMiVc*S&E8ap($aHx26#a8#yZ$NgOe(
z4}Ww2S&5K?gZLx18h=E?-N=u!6JHw?b|d^(fNNala8bvd!RG`Rj}@WK-QvnhHXyy>
z<K^WF2p^g{I&d9=>yUs<gWXx`gbiR!(mh6-HJ|THmWz=Cd7me47f!SU?qx5qXYL|m
zV=5goo7=BWwtPe4D{#b@-u;FQfEiD*hu78D*Iry^JJ@Cdx*3zAXbmlAhi^1hjY>c$
zQE#>{wC;DG7stH5vccnZD=}AxbumK&9*b40FiLpsuIT9`$7BqP4NfRNm*-p*b#9cs
z;w#|1a^1@b-(-BeXZE{Q1A?z3cYd(+peDx!mUrB?r+j3!w5wyy^u6{qYR?Nhn17ts
z^QHVa<*O8$RyNkr18Q6r{eikL4A9rU$yjA{=;`n8IDSr;wGAWyV&r-!C!d><kfP#F
z<NpyKXZZNo#IS4$`1twe3>vIrjtnWNfmt@vOl)TBpeHIVc(t`t?J|3v^No^=2ISW<
zrqLwgS%J`#J(a7B$z_w(WcQuK6>P&8D{jkC+NgiO)QZJc&Ea)tBgFp+ys3boio^Kw
zM$f(@<`d+Jbc(z<npU^na17S`&Sqey`|Ve8*5?ulv9WTicqo7JmOapmi^!T6furGV
zaWs=9B_+kS8=~8@rTw3^Dc7mD?B32-OYJEJbtm!IV494Z30`MA26Y?l<T8I4<{4VO
zM8YlB-*FBqc+WUq7DkP{vbB|V`RZ(_x%t`&HouyjWk=`7YoovU|IK`zLteX;i%<O!
zU~MaWF8cv@+L*ek4*|+^!^$90mLCB8=JN)G<<w4jRuRz4KvQR(BHOe8olndcuOsby
zu#$;tjF{?JTzz;7vr8_;Be#DF%5hcI5&*r1!aH-a2cJ$lCH1F~#8zbZ`kCoI9neMm
z|34j&JL&8C(vZemfErwOI*Q5T<m9xeWNF3FFi~2(RcJ)0b3?yYH|C;!A0o4USrf?(
z<LD14<_6OAU0)I^eZw{go=c5h0(`|S<18+~zPKS&)vCuk@%Kcw1MT1%J!U?CqoTt1
z-3Px$(VEoox8$S|6600!dzgzxrzg?0uqb@>lzQ~tBc<-~<&2k4O(itU7D$JU4B?=9
z?8eH%SkBb9j&%Nc2$W>PVMx233kDENyG%I`kT=5KL;5KZ$-DfqS1hvE(JrAvuf1G<
zZrV34?A^jsV2%ym;H)cklheD=s_}&sk)b2m9eR!+CI>nNEcN#Qw9K4_#axzd!|3#M
zU33g1f=+caP;O3O&=JD>1f5yflpN!TlmA9$%y<w-3NiGWhu?Kja!L>7GG19owgRG*
z#fY#B+)lV_rV6^2xg?J;3qn2mde+1*g=aheHxogd@lB(hDq@yy7_8!l@_nCpJeos6
z=82fpcE?38^Y>#mi$Ro)aUc#AKL;_WSDC}cIXWu5Q*c+@M|<<e>%a#Z;bY8j5tIkH
zgcFwg_C$Wk6ByR^GaFv-%IIj0HkP#u+rIJjsh2Ro+=n4m|Ci7*8HK{#E-&4w59(N8
z_z7o_xTySZRfc$u{y|)SpwAI^h+MB`PJ#={VL+DA%-d1-ac_;TW&ORw`sd?9K$K9S
zhwaAega>-lda`D+)ORm@vA@;+E+~?%X&Gx2S%@rtbH)_bGM@P&JV(#1BBy5e3D@x(
zeyy)UqZpW23%0`WC5JW;vJ&(YsmO}qPBT;y3%k31a#Wbjtzi7EF$*v6`U?aV#R1va
zJfNqo;4m5g`qa1H4P%bZi=}jUs3&w+Segd@rLA`e<9)>Ypd9z|vJTPz4i|7T_#&aa
z?QH3Icwuxjk__pwshxCDt3Nw=n>f(3{~@4Jba2vB*DIHB=OyeE?XH;6b^hpJPpu$P
ziC`G$uE8ca7h=RE|5hBeWB7CUr)cjjNR@@^Etpndro$2|%^U4gy-0`dvAGdEE4BEt
z?~R;DBhhRXq%zFZmm65U8vAIH$&!4w{uMFYM%;kvHJ1ddk35GL_WELc4p6Z1?w_Zj
z<oMpOnqK24_uk@>OC|{)tx8yS>{Ko`xa<v0=c|_zOy5oT>i>w-ZuSz&DF763zT#wr
zm3L1ud+#8Dy#3~N(O2&ia8MYq4dxO7CUEg7<`g6y_Z_qIX_e$RckU}2C}@~PAVZ$D
zbe3_4g+C>tbzX!k%jdLHBVk;OZsaoHaeF>K9M(EFhl1dynpg1tGA=yaV{i4=1K_*0
z+OK3zcH~baPfNTl_Xy#}X=y%{=PWz*oI6>>YVLpUvRDGZL=49b4HUFeLz9HuS?tMw
zOPfYs-z#ZEge%%F5CWWih0!`T&+NE#3LE(=RZKKMuA&)4Z$<nDc^Yop5hF3jD51i5
znc-^~g%M<}-h7NERNrJpKf0Uo3{ra8tfq$6#Sv?~yvIvY=v^DZ)WB1QAtHk|*xm?t
zJF53|$fopQ_4K7<mViasF|tQxP<%mF*LY;^nC8^gU7JlmPXN%&o)kzF>-x%oPp5|>
z9d!;JXP7P}uU)pcu&rAk`BWHZ%YSfN)sQ0L=0?BI;|JY2A$|QyGnnZhCC7YY4dZrW
z1`Uw^fdOdkX(=gu(4V9dDPs|oHYpmr40jF+CH)#3d3o-(ALpr-BlmNkmEiDGdoCTV
z(KQVoOf7*<O(EmhsFVh;tc79Z^VP#T2&z%;*pBeU;|`Ho&1M6qg=c)U1fCGHR^X}=
zu%WUc5_mLw7y3u&tWdG+&Xi-_Ic=05f@M2Q6mC9b(5*17B);>s+2TXjTU!|F;cdQ3
z+U>ly(}*?AT<o6*#)ozGtR=MQX*xcLrXT#&tY|7XjGYt`H<$r3)7{~Khl+S^cOkBy
z(`IV2^-Bxj8&FU{i+vNOf;vTs-4UAHLMJw^c@Y<aZP)RGWlBXsgdAh$#L7;@USHj}
z!h5Ekfw4q4)EnA;?|Va#f$XiOl*V~&P3|>K-3{uh3L}=aFFazxxzoWjL|o3NXJDIX
z(a{jtF}<DXOmbUN2U2DK#euK9a`cW(Cm^|}M+09Q0gfUG2j7+Qwu}cmkBZl*rN?lD
zg3sZjTJ2f$T>m~Z=Ckd{`Sr}wWPy(L(~pMu1;Qu0v-tka-o5ea3&kRY9zY-jgS_rv
zRpm{I4e-y<7glz5a-di4A(wrT(?)XzNUPU--qr?RGeF_2;$}h{97QHz>};m-CY`rj
zRVaZiD^6S<i`sJP-LqVmlIiK`E#n;>vU1}8BM<8F-jfmq2G=Y*>BU?6DvQF;*|1*m
zEd0*Gn5?E#ezhXA>B*-ltg6Oh7VaQ6?gUj!4muI{JUeopTV_AxYE}t>3+E}pim_zl
znJQFTjXv3qAa}LE*is(h=`2=QWOKiSZBq>NF#{N)=A|J|&38v<M}W?7@_l~|W7n%}
zV>aqC-I1dBcq-*G!%(0UObs)lkO6->m#;|o^QZ5bl8LObjU|H5eYb7wkT-^$^l(0P
zXFMxDvl2MX(4k<D4~$Y#e{*`-sI|9|hXN%A5-`tl#R(hQu}=QOr~l?#R{)}!mQH)2
z*grlO-n5&<T=HAS%c7z<%6@aoN7?Z!RVi7WsrK<di^6efbPOysh$U8UBKh_w+<Cp@
zEpT9B9URYBX<nwOi>;iV7O+EB=>=g@b^r~$o(^*6$(pZY?QuEm*1@-|u3=?41=~R=
z0a;aDJ-v;dPKsRuu$b5RWdxZ$@LAs*Hn+ICobD<N%VOtPZ>>gJS~K3t+aMo^jFosB
zGG3{_)nwnB5MnP!rj!|-6A4|kc7~a%FncT|6~<`9{rim`WG2v4JUAdR(i~R57(a6Q
zOA%kKdz@X@U2G~6n)tmK?EuJ8cg%@MY3}&t8$O%Jl85%9s(o!9+81s_HkNdYPz`-S
zQIOX(dJHt?&;rn@aWNa*rl`kZZ)_=<n3%M(@O3wZR_vbr0i9TI=qZiH`&xUm5fVEl
z1CY;`5oVwPF0@#5{u_OL%s5uF)Qs?Rql0IicugM)P4PL)YA>fS?_H&`a!nk{IY5j8
zP4k^*8bIhkzZZc~nsMbxvLk%4f$@Q`Y`&tAEjOJfa`ie)8t5+!77u6e_iI=(#3Sym
zj;VlRQ|d*j=-xC{vQJO`dG{1QXjapiV4#!Hh-I#6=wBZ{M~sM$4&^Tf25+lTPE`%0
zTmP3_9GkE}k>zB3Qke|U@$X%c+pOl?gc(RSPx>4IB&sjZkGcLQQrwKn?y53eOKf*O
zG8^L=g4p%TGLG!E+I`_q9<dxNu-#Usi`c&;KLOXiq=w<e2Ydf82usO#ml0pL3*z}P
z(FaI67fo9@ZeSGwI`M|P+TQ+jMLApvSv2GA`5GF^(#-~;=IR|NHN*Sk?m$H^I&Aw?
z#L->@)AK^9n82^Cd(xA-$O{c1ol!4Siv|XMnyHHOXgx{^VZyD|^PS0hTsQSPbT&lX
z?5QtC6t-#KdQ`BDHG~=5ffj?<wykEymjOZu4Gdo-+$A>)sMmA*Rn0r{U8v4)wwx2{
zPe>yd8LDVp33lbk##ee?20ia~ZU0@@=8+Gz94}Ks&@#yc*GWgAG$D_9I(n0&m+Myi
zld2yeBT8N<Q4Mjepi`-U@8>-$s|ZvK1VnR8Ko!$rUt!vP`pmJawt2Me`RS>ick-yy
zyK033qSvn<GfL%GMjP0%%291aq1KedD5VL9^dft7-?67>WXQ!}P0S#C8Ej(Q@$MC(
zmSJCKjrChxY<qG3<h*&Z>z#x0UEG&1dDRl2mn>y633kvzPSBS7R9r}c_L9h#C{;={
z!Dpu<a4aLZtbfa84B7vYCSl>-6E=)5?*!C>f7VIy`+v;P8=`sL*+&Ccp{!iMdDM70
z^}^BFIcKgz^cH*9C%ET%484}C9cxd`U(hWj4hpDjfF+Z1!c7wa2W&9i1}SLZ2VERt
zX<k<qfBaZgK`YI|(r*m>F#`0A8dZA(bv6kgLLW~xj{0Ic@1&-t`V@U4iyy{oWvs`w
zj#0w<C8^d*Veksp$I@kn&ra6fUXVRNwNxFHUpzA$Gd66Lt;tkby1U$`aiC-V8zRL`
z2}#lReJyWd(!A>5$VCM{xaLZdg@{i$j0UIzKt4Ui<{UYPY^~U)n*K|G;@J%y$714j
zwTJ6#x5b*%%X@cC<%dED<9=rnG^C)8U;_jacJDlf1xLQswl%Q6^$ZW!6p#Hr$cl8h
zdX)M%YAqKh;;eaGQfdQ?<$eSYe|RrOykx;OR#KS6|BGCp7vRIRA!O8j3Xpi7fYPg+
z?+TyPB6rY2BYsdqA1Erxk@g_<&V3po_xsTSDuM^$Kd6Y#AN3!S>0-x)@5zc;gx)(X
z;u4z@29s50JT804Mw(Yj(V4Rv>~!IfNU}}9@bh;Oo15hZYs)zs5P10bRfa-p^#R*#
z|6~-3iklW%{TCMA+xNNI)Sy2bYSFAnP1R1<TPC7!s`1r0LI^}0)3{v*N<HY$YA@Eu
zfXaB?O4pj=rN2rV4?IQ92T8swRxqvsl+qv><Fn#oFe(9o-+Z{Hk8e3;M8^pKn--4V
zxD(<xt#3xxnPi;AGL1HJ3tWK|`cwj&1;pvjbXZJ`A^26P`i4&2yWFsmoRcJGpEZA;
zjO1FsdD1%=+l?VOet!OsfyUl3p@V>!EFW*xI5f`9Jr>NMpU(Fh-O}2&Xfp@Uj&K+h
z$$3%#p#sN6_}+%!bcm7r>C-2p_fi0#Fk096vl;{{QSX3VL`39x1K;HRB+#!;d#5Jk
zBQJ)<dyafiq_FXn$du~e^&*2TqWYIHWW$?3*#i`iIIjazbH@V_Vw9;e?@?JpBlQOE
zePD(Gy&b4Gxx`tc_E(AdJtM%8EP-F|zs>r4>C6A-0}QR${#~f}`vCr6%Y6$dvj3ee
zSJwJ8I|T6l8eU_7LJ(6S_jlHuy3TY%m~dDd&;`y$_#IvkbR64^OS_6wVM~?!h8@h(
z`$C?mG=WFEau9-pf*xaqmj;IWJ`BJ#RUlkkTqHa-H_8DeV7Wr>gD@YwuA?lO3kU>;
z0L39t4!MgH7-j^$lwGmUa8E0EKt{q@LR5GAhy&H`oj%u={{vY8f;Q=CXrS_<3IFqd
zMcG?6?aA+&{O_(X59L@Uolmv{uXYK(O0E6h<|w~}XupJYCHKXNiH+C{gYPM^Rh^Yr
zT3X)pUapG?R+@R&?$y1EZ1|F(or0P4KZ{Q&q+RZ{W0rKOB&`RxDodY|l056J{Ck#x
zNwpTsYgqFQgQO$y-DADPav9nL|4lU9|7(^o1dKP*{N=f0cIifER(PBv1KjLvQq0ML
z0y~B~rWr}AWlxbOEP~m4Vmhh+kIT?Ns`B-<aD9r6^(`ywf!#mr5ToOUaN*)|WpViA
zTTajQ&xZOp@bQepxX*xEI5@D$Ef#!g9n2A;H?Ot|k5gcO$pUVPi%I++NDzPmKkl>p
zU(1t|3n_t~c#N$;w}S}IzW)BoA~O94<yQZ?B_N#!G=RkoU%sRYUyE7;`c0swVExo=
zWGj#*{!>ImP&sa8bH_9SkggnYy7hl}`x7<I*7hHYwdMk#MsamQ;H5laNW-I}{T(uY
z@B!Ly?`nN@3TT|1M_A!Z)@y&38SYy;wAMR>G|fOaYL3Q97^2Vnzjv6;>+kt#e*b>R
z5d}|RFR-(-&jX^qWvnl*Oh7^a+uq*(<m9uH+C5&{EcbBr!@?2({qo+n^$qIkctDjS
zuo%m)!kY?<^BqhTzMrlK16k$$qZ5XxkhO;=N4gM-Ox*P`kl82#iWwp10jw|hcWOgj
zjhybDP2&?leOQuEvm6rd)^UA-K<_rAC@5HFPJvh_3C~P%PvQV(suk!N6xUQ^8^AwK
zo5&oQkL0_Ir3vF@(weAA_<%Px7S$X9J7`}K*6xEHj^rW$Ivhj5AGsiVb@JzlkuByc
z)t9im1Em!ik1ER@_4D2Z0(QT7Zmuy<McWQ|EHl(1<Gy)-cp&0!^AO^#u`Y-9y!rF<
zQeu7lPtpAfbnMSMWaDoh|AU!Fgc<L~ZI^rxR1oLkJg462ft>?t&j(TqTshZFf)1IO
z{@BEtE}p%;;^GO{Wa`h)o(&BTGZ-Dpx}NP|0mi==v^MehFRwcAg8t6mx3jOSU4*c&
z<pzb@4<OuIKdM*^$zmY@j<j6kr~fOnmk~bi&d{sz*O!RrbIY3q+CwaCFGGolJfT(A
zLVD5j50T~xLw%ozaddQ4q<(tu3S<9qg*}=z)#QLP?Cq{GyF%{0G3TkV+kzJnIqGm;
zUR%?-3`UW~y=UJ?qe@GerUZpa09_%_>H8_(v*4m4dHu*p@!wVca%ug&G+BT$t>!<J
zX`+O~;>w_O`TVnVVs74JhMO4{D8dW26tQSYSa|q1va-0}ZG-)Cb4^z06>LV1uX?sa
z8Azcwzj{QZdCMt8#>BwpW&{jO)j)-nLxq=DbXflr2;AGG!iUw7wgG>O>vi#;im}3R
zPESr|H`xGs`6%=UTKdYYgs}!uQkET3vx2!IRFkoS%5|KVOd#<Hqm$y*2d;Vv;Mz5)
z3jmo~xQ-ZWK2W+jrxA4=;sjJa1On){t&MS|Fhe54CFba&GG|*SY&L9UKf}?Y)wpyM
z$K?je(W&Wa=^;*!?JEu>f?ab<yZbu-#9~u!sfYY#+Aq{PXsZKv&!NBjtdYAy-k9<<
z^Vx?1;#8wpTQL-%E6ESa5C2qA#z!{VlEIbKR9C;j6e-A-_~|m)GJm_wprDmu1HezF
zeH|6qdTm6}|I@>_b(DD>$g2G0tfd<P;F_3M(*)!O6)_NL=Pqlv6tZO^p`G@U&tCdf
z?s&Lxs#H!uc{i`@JqmkZ6{s<?wwg7?3ZpL`{NrW@pB$98i8*YO+|uz39^PB-u=pwa
ztoTi&^l>Mri>icA--MY*{Ka_e86n=i+R&pF65hq*w1!tW?8UW{$*^R>8>zUJZGBlH
z`bYZemp6pKg^y`$5yY_l00|VmTt7})pL_yP>vGaMC$hx+)rl_1nq7zGZ$%~Be60FY
z-bw3>PAtyJYmL^-Q88by`nb2w^_Mu=QOc$s_&}Mh-IWluJ~`ogJN(%#s$jE+P@ae}
zkHgs^*A)UGd#iGEIy^ElHz&Lhan|OFsH#@!7Nc?qRCIDX2KIl7LEt5PJHGp#UyHb6
zn;q7j*Miw>+hU70wc?~>mFQoUH^2BSzDRgkCwj-8?4=lcyPA(fuU{ud1<py~D|pT`
z6yJ!FkJjAa*DmhwT(^A;2>sBk35UE@@zwk4t3{#7unM($4JI&PuSAJR@v<D$pKR%1
z!-5Tado^K%j*gycVv7rY8RM!}XN`cjgD?ANqOA??$t~bdYcDwnOC!<%oyG)~8_!t&
zvDvc`ukTZ1ga|c#c@NLfZ<}bxmm=!jT(9DrE7pL?Sx+{QD~GL)WBFM5e98@KwOsxA
zY|ziX1|rVRF!!Yb5$`Z3!U-pJ8GuF$cP&ND6$s{QtE<GfrX-gq^xT^c1~aH-h{#^K
zxi+y|^tMDNZ$XuaJJ3>LpFd5jrIMZ~jhoJT%NWpRZP^3koC^zf1~TjrB5%Q|qlTCx
zZ%@8qx2?|*KTG8DS+W*p#iW_`K^1UmovVDYUUN2Ybq%^^77oGoIEwyIq`zdoysZA7
z-{5&Qm#L;hIYo-BE6FY1?Zg!pBV*}k3mKS8<g3m!Jt#SN=dIiGg@oA1#};%b=$Pn{
zT{WgVgy9^SdbJmRicsfHxi=VF4)Y(ZIjswqzZ#|RK8yGum!ft_mzFlnR8nMpBY8p@
zgxOw(&|$~$($oGG!UXZFmq;AdPKFrIe40UG^3$}`)GggeTvoT*jJg_LXJ?^!>GF$F
zejz6!L&*369igw?Ng7ig5$qOVJA>G6U=4J3KNOU(jzS;t{`W^g62AW^Kz4(e_gkgZ
znrjH)XNrzr0U1Ooe21N(?B0th>v<cybVE)?ar=#dWDzSsH>K@j%Me@0iRSSA1`cow
zAn6KQl}t2RKmiSC?#pOEQ|k@pl4?3KWL4~3z$hKs{X^T<+g9=-t1CBViz!9u(3j^<
zhrLe6TZ8YReH_|uzIipzs_zzg<0IdKAa9(%XH}pOas)I9yBRlTrNElCc%zP$#KO-M
zOqXEcR_wMGL4f5hGj^T~)EPbULs<_UIYz{oXLg48_N-!?+o!G$5^;0*xjO+@+A1$?
zWbj16PIzoY(2B_&pE|!M&pWS<0$NE}lSwH5+fb3aB>ZB#aV@;pPV&%S-Ia=koKQC0
z6XDVKI4sf4S_I}-HVQ72KSz0PX_G80FZ-C)A}_r8kQ3*n-S0`t?m!I3hP(-(pn!#e
z7|k2E-mZ$f6(&Aitmlu-{APNL2DmamwOT1Y$}EfQ$z)9J3;D5(+tlj+F2ETeg319w
zRC6S|t3X(vC9!u(sm+a9O!)y7+w(gsMiFA4HV6T|T9D)pDPqN4M^Y=S@ph(gJ5I0k
zZh9}8sj=wChS%D%AgqXCVt)0>&oXpdCIPS}p&yGhk2lBoX}BE@Han-szDigz-g<SD
zliGhvL^e~-)`7FO-$I90Dx%%7j>2Jxk4wrP(sd36>J~bw@fr1m41+QZ@uyVhlCtri
zdrlWfi1}0+Bg4%^&0V|J52RbY<EwF1E+vD2H5(L9jQZ67?7FY7!RrW1X5{07K0n0U
z+5|W(19A-P*}F9>5XNlMZusEH;QO!PgTn@Bv^ix%G9l*|jwBT(SBzurmo~?`UX*m>
zPsd7L)i?xxK$!ie(Kl3S)LUP|dV*p32m1YIFQ@Rs%5HSd!w}n_kT5Zp0@X8Uj>n$0
zruLIp$oP-9w+D*N41IYz(P5v-)|)9N!yC0rcA`TGeOncwP2Q`NQ?Xk3kb?ugwYi=C
z`6W^QbR08fETmxNM1nX6v5J2dJsyuW4&&kf<LfJ<>e#lW6Ck(*3l6~@g1ftWaCdjN
z;K4(1cXti$?(PJ4cZaW&^X@%4_kQpF++(l@y}Q?1J!e(Ts=N6@u>R$GDL)X!#YFq~
zk5iQWdq#M)2uzcU9hqC!C_qiT=c?&`H2+B2s#&l0E(GHGI4jS3yw-G231sO0{+-Fu
zY4P{eRBWZ^zza-v($F0?_W8qnn{WE6%Tj1L(h_6-PyIWmoA1ze%@u6=^&A?de0$iG
z%L=;o>U3E>PmtnD7RnARSBfyeuTDya%&wRSDMjAJ_DI%cv?FZ}sV<zI-^lKUH2|Ih
zCdLW>dMo@r1oi6(md$@>Muh&fkWxPM@pz>P5AfWivM(#cu~=zUAJN5{nrJ3RFM4<|
znBINik;%{$l-Tpl&s~~tef;Fn!i6|rK=e_KePrHi^UL>U`c%GZlJG%;=%@;M`kT6S
z&-dtSp`l`hD$RN@U(6W<CC+BYNuIyGIqztbSwCtB1r~>3y5-@hpINJxYQI!nfCLLZ
z%MYS26n*r*Dqf?+B>KlYT=O;5@XnFw8MM|WeG3a>iT$F$;PuJ!B%ir}p?Erj2kMu(
z8P^#7a`SRw(RiBdB^IN#odaJE>w|pZ>s}o8K+m8ELV7Aesn-lj^F5_yq6$q#McBk_
z*6jmP3j}2}&zmAE1#P<D=6V0!JRZdI*2*BC1FluYHktmgjyy<^CyTiTFY}8<uD`{H
zg+=awXK3yZxa3#f+e7xQiH^*xeas~u4@RwbY=&No7s--6AAOc^HM0gu6FIFWIAy7q
z>#T;jYju*r@PPxa^n>$MkB7Zo*+-6D=(-bjgQ~KN;3(Y=R;P^;iY5GmMNuOb7Btj?
zSe;U;5AjJ(mT5+8q;CyW3up_X(xH0?r(t$1kSbmdRhpCfocmgNM#$w&aT9U*g`tKt
z+UeuV!?L)&DBcFgi>Dzgpr&wozNJsE2>SpJ1uw69c~L&1WKm)<v_tIbe8g39bc4&8
z2eQ(tyj#osS$Y&$Gm5Ey5IO`Ex|>FTKa~&q?>#0f0|q!eodHf@{R0Dqq{`hxz+wu6
zN<dR(_`Dc)xs4XdkS$u;Pj7ob<;laH$e?`e&1oOv#$|f|J4tJtp?zBRz{%87?f#0$
z6jT=GOWkI<dP!<PWHz*BPG~c<OXtL?XJY+S=SJD8-7IYw#pb^xROeeBNy?w}PH#If
z^}yqc7dx2#rinyp1b6|v0prnYwKJ}b9F7e3>x4TRN(VnGD%OqFbVlBDcv3;3nO+F7
z+0jISiXLMfdUS$`Bx4A;M2KdkbICj<v+TE@5%8~LN3MN1*nOxudq=zWt)5NQ)zz!F
zxNFPJs`d;DiuN_pGOJZ$Tu1CSn8nOTDEr7{N&qAru{Sm});GYQ%sbJg*dJ9y@mj8t
z2t<Rvw_b7w>F_>99#yd07#xhQCwi(rEI2|@cg90=T%;<iKq(6aNrQuh7Ay+J)l}0v
zU1yj-JAI2U?x7X8O~jm0dJz+P^t8T-e#G@8o95QJGNX!%Upk6AsCu-kiG^0af{GUc
za<bT(_!a4Mn%Mf$e$K&;;<p`&KXR2ANr0vw0&pA?<PPJPF1xa3cGEA-VTon@JnZ|I
zFS9H@*q$+~VQ5bJ@vmWqJ-IH*ZuqnqAoc!&P)9Zc@GiU`Q72)L)6$@nfLYhcQQp&z
z;YUp0`i4E<RNTK>Tz@iLViBeNL!Z+7?tWVCXtF3RD)HUmy}7Y*Y0ZS{XQzm-)5OO1
zsvj2Lhco9YT;m1DC<fbjsqsinW$ZVjG$eojPGfgiG+A7Tt7M1bDOHFiUZpyN9s(vU
z5&b30t+qwm-p<q_&}PuQ`h(|=VlB88knr}~MEZ;qX&$g|)6meU(NbG-8gyq61u*w7
zDa)M8q2gcKB8z9)Q6WU>b4Ne-)P<DEB(j6f&dzRFl0PJOcXxvok{2d0TiOXF_g?-L
z>GK61tW3KtI3v-X&W4wVO5+MNPZA>%4vYVj>!b@XP=A;a6$H5HpHV@nB%vWd&lt4=
z^TnK({W_Mgda5Ik^$nl9IINxgD0ay#<7QvOX)0=?tZ4EQdpG2_j+C~~a`%>v<qVQD
z3n!)El{KM-j^za}tI3#W7ncO*gl+xUERV9_wy=*ZYcL25t`ijw2VDM6K{;DSMjvm(
z1F|dqYRy@`*4`Xng1cSqy)2g}qXD^FZ;)NIpnya+(9<@SH|{q_$P!PFr?2D1$}+6%
z;w-e@T5}_ZdLXp)Z=JxEJBnrCxgQEBV&M6-MJgy-mV1AF|L=HCOs0z<!S8R4jY+q5
zb~4Q8XwGh}+jai>lZ+6girQMhY>4G(z7odEi@Tz_T4<HKrPeFCHiRa9#0Z3z$fr}V
zh<5A3b>cr=zfHtHQd7fC`5A47Ms=M{eB(<%WQ0geR84|6X8SArslXqM`KcD_J1kTj
zRa)fI55fw^r3i5o;$$FQl2;Y+QxctiZ&;Q5=bvsw7>S>l=n%2oO`}C>n~%5d|M3$j
zXnl&6%R2|fA5qk6&1OC~kS!{IBxeGpkzUMqkylKJPA+#*(|hh7_*A0a^p;wkIjFMo
z;76Y#+~~kSN2id4kn-_jtzs~WIRg`u5SO-gjpY(FfC}4`Z^O%sHTG<Yn|%#&^Cy;w
zOL3GD`<E7=qiae)Fg=z?xkeLB-H?4SI?`fvZSB2Ay$zyN661F!QwIa?1G@depqc|W
zDJ}oUp!<ThQ!Oy=D~^vJGsugS%i($2+)O6x5r;=cBp@yovzpUs!{PM#NY1d4KG88x
znk&)K(XI9Cw7kF2`6DX}Sdg-nKnNPG?rvF&sFc*y;I}IWs5<M_a3Ipwgef9r6y+;l
z#4h~tk{Q!YN0;c)k~ie->B^j0N?F|`(e_Bt4yVo8d;VLTakFruVUKCTsn|&Fxh<i3
z?}W&Q#}lD7eQRsdRjM*ueedxGW}&%s*G6vb#rfVU;PIl6>d5jg;VMrcVWoosheJYg
zq8)cKg&W+0#UEFw$mjzIA3J(_gv=Qh>kcy*17Aw=WTdTdPlSluSNoI-wU>~^j3R^u
zfT=`)Re++TJZ7mUCM^yKU^7__zM$BusjHmuiq_V&EQRD=SXkK5`ozF6g-LlS7b&UC
z-KZ6fw*8{ZeQ?@@77*zMO?>+qEd6`wIxfkX2XX}?%Y?ZPFcvrd#6{ndx6$#RYmyTN
zWUGIs2T`(ak6k+5ac={1wr@6MO<<qVfqGbki%s)>4|rHH|MRd=xDUu<memnG#Ongx
zffYv<&U+v5CdNn%^)SC65`|j3$NhsubL<`1dL=@7fLW>o2{G~JRw08~-(>MuIl0K0
zLD_skf{qu^AimY!c=G{T-k;HmC^?r#WZQ$Or2jhA{wIO&k4tsQ1DnSv0ik7c>l)SS
zu2~4BvlwO+?CYiwvs`LG(3Vc~6Pw!6KNt?Eci0Y;_jXOQh^+s*R-9jxL{CYJhKyjz
z@8A~ld6N;b)sX`PnN&uZ^5ODA39uDv)*#^^h0vBs_p7gWam7+f>+aRv*!nmgh`+5=
zRn9H!f2z1_$%*XToVRff(MGtd<?HdVyob^~_A>(Vl-%WFTiBID`5#;FpC5P)N!v$t
zP?gD!Bw1&{tof*&P19KH;D^NZ<msJ`*!*8SwYw%y^E!sA;el3$;*jQcGw9{`Q<)(`
z>COmcf1lqpSkA728Iv^fdT%(Uj=&j(l;Ae~z3csatve4eG`(esszhg3Cp_{^X3g;w
zYnqD(_5QmB(Ths`eP8wuZ=u=PzE9_65xyyQ5h`V5WSq2roOA!Y(sp~kFZSTY^<iGE
zS}JEF21KO!8y<H`#KEMMlY27{ty+2zhIr+TtnM%LK)s`5V30%fNF_tY)%`=4qXz{p
zMT4$RD8r-iUbjg{=gqQMh=7?BxLW;mPr-*3T@#%zVnHl~!UW-vX|5i{^He#m;q2%W
zHN_qt6VRoW<KJ{4lejU`(j2!}s%{b)T782=a6Fy{(E0~P0>W#V;;2(;<0V8z1;<NV
zS-mzG*`3XTrl%EMSFbV}>b;)xSn=502!<u4CaOi8VR5g@G>ioLKY&35wGRy;6N-3*
zJb1NUv{sd&vn_q$Rt(cT)|u!9EmVhgo_Eq@03&h45mKz6Fh1*%P(C|u1`v-zF79Uo
z8`b2#hkxFoKi?4vUq*kgNPwf9#z+X`&(D<%OKD@$C|ZwSoy)fEa$^M|-Wr|E6v`rW
zs&eDPK}l+keBkCf&vHZ?gYLo@5$_-4tYK7=67;TPH|t~3{oEp$J`rSKeP<v}@U+7M
zzyBeEqfR=Xq}m^se<3PuwFq^85o<0!y5@e1xAqXeWMdyKEbGl>$k|D&)!W%K6m#_}
z#9-?^Fi9cA>avFpkHbxKiuZEgCn_!0!*L4NlLMviPh)OQ>B^%79F_VV&h`~<BW_^j
zt6x?56k;Ai(^9zYaW_dMsTZk6Z;$VlS<jW6C>Zme9KqRG^u9Iku%;N_#@&7+RMCtQ
zrMEe}(VV`#mLu);{9}{;{RaK(zGW;!RWPVXY=MJ=o6Hnpye!qBMP{de9T_=zbTuy&
z^0u|tM_ym9W%%JwMBS9oc@S5(w~6&}QNSvtH-Ho&pt-4*3wwlG$lX$1#AT5K4Xd~)
zQ*}zX-t8D1MEfM<?J0c6GTRg)qAh|HCX2tt?l`-nSukgtP#+$L7c?lul>l!wiHYng
z0^lnf7YabEU9+>FQ<`Q<eAG^?F1S?<_eAhAyq?|mo_i@1nDReusLX0#%~$Yol{^`m
zP8iA7*W^ts?Jv>dUoL~9vn{mO$k`@`P{!9y7am7c>IeF$*y#TMA^`vA?1~M3!{Jxk
zj0wbgBSx%|Zw7Uh8aW=pbA{o>l_TE!g@;ojjI!4SAeMY4F%lh^rNy((7KW>QidU+4
z*{28Q#cVIOOuKtXGgPa4&7h173_?Uz6YZy$mtkwo%}+Flw{dYNr%{}4oJ2*bJf}Ds
z;hmi1A*!=%xBBxVNqQVdbUxDJoiqF(blX##X5;3I*0pgg^?CdJXht-||9?F(PAEm(
zQ$yD>wa5mm<yHs=28DG<5~gs>hxOItOqcif=xL6WGK>Z6`T4^*Ny+8+;3jZbcTo8!
zFQ6i4+k3k6fc_L9#LouC`OHk!R1&&IO2M<T^~dYw1b|X%qr;CZR^RUOLb1+#uPru`
z%lU;sI3kIRN4W%>rwWUN1oP*OaA3vJMrgM-JRu7=T(9(ONRi^~)D&^O+cmqzu?4G=
zzc~N$?{e=y7u)Z0SXK@UmeOovklWfq17u?ZIUvy?$DTq8h_Ilf#M<pD|H#3C1reEs
zG}_asCfxLS>w!8<iqDkfhO0heco`eTL?<jdI@{*J>Sq;ddCMXwQn26_3<;^NX|87z
z^Lzs(O0byNoprIp6h{vo3iZ*x99B>yHku?1G-IWxoS$8bWAV<%{PH3h(}=aOP3Lc}
z54h0u_TL;2p^&_}pasko&^bge(RcF=2p)BjE)*D|(zR6LRnOKs1Yoh)aEH9_HD|j;
z{wNzbox$L7*?m195xAWXDH=1FyumkjfCR8)2`+EByBKKScL}`21iY`_=`7xe^z=2}
z<~KqvdDrU-!88oXonQ%Hz`+<{qo#SM>`CZ7N0IJBytEpmr@hrUksZyOvOSkR-080v
zZEbCJj?RLEKD59KbX{B*%Wzk{yZyeo#SFiELs=p@Qb~UX%Ip6!xZ#~k06r<)@N}3a
zRk1zGh8^4-{18!=Fni+Ysx20~^Hyqo0~-nmadp@m|L{EwmX)0y^1O7(Nq6VybW1?J
zZlB};;?`2AjoW&yS~nYUzPj9oOd)M8%kV72xzc4IQsrh-y!rXFbr>E85`FTF5F6Tz
zz%G$?(v<QHtJ#p}w=W43_!m~iC)aWeE@V1n+lf^tC>y?Y1CLYA8p5?1bGomlq!V#T
zaU>CdCdUq=>|dc@z&crT#Rob-(i@$x9_Rrn%h;7v4+PpvZF3YH2n+0E=?EfSf!9o0
z`4-EUqxn_ZJav&!WJnq5awyh<k9|Ou50Nbbr+oBT-5W8@)bp+&pf45JL5gZ1;O`y+
zbw967>TO2r7@EEXnqzcs$Jy9;Hh*e1V$>T7yQ#Q%I3?3GK-SXT)03@MYqsrGTC=VA
zEjp-qUJ-p!t$ln^vUt6%Od}ka<_BKw;x4XkCQNYw|IW?y3Bj*0og%5PuQ%axU2?*S
z>HUxHPQI;<^t)tXwbGL9n7r5EG)6^T-3OodleBA6-;%zE0N>>qG96N4$z{U&bS7|h
zfbq2gV5JHbAT(M%02f<kk#v?-S@WULb`k0~Ck7y~-`cMaSr8fR%jTy&*0b<F84kKw
z%)j>?i0<v`6L~f|qwQoUMMxKSX;>g40UEO3#br29T>kD$U|VVw*L1{$NhGBtbu26t
zPbMI*`e<`m*0M0(ZWtOGDxJ)UF&xI^!iK@>n&`uWDjb9E(rUH_#*HLr9ZF1!>KcxC
z{N0Hu3WF$@YoU7Qo0zMYs?{pN4~)_B%A0{}q*y54m@g(o7vI0YCml>HkM=ZRA|XXr
zxL&r^J08N58LI4#;;f&Pt$=qtES^*KDZKYfR+n0?cZDI9P65w-Yra&6s`kT-+?%p2
z=Uy9(o47P}DUsKZSjWr^#Lb?8@#@R`5D7Oou8+^kL<XOyikeyh)8p@bmHh$NnI7nV
zB_R{gvG#LWNJzjJ-J7nGzC$qh>?XHoAb@kP!feg_9iB+b=p!8dgdb(l4tVJ`G_dV0
z*1|kJV{s}=hJ}YuRO-8Hv^e1aJ!Hl!<Mr_+&-~(IT;nL3k4)iv6<~$YgIpbfgFAIa
z;52nJSQ;CLwtBjmU-ce@o=F~d<$u>SV-5nM?cktdth3bN!u9C>I5~bVehNIFni@t)
zgrsm<VfZc)0dQU6acn^UrNk|8U9&g2O$iDA^Q$UDK7NKO0~L_nB8;hx!j0LXgHIwG
z3~6y^j!cAsM5W4!_rqF5=dcb3Q}s5BbE@%T0+Ij*_=&Rnkbv2WxU<;&$3OqE&jpd}
z%#>gXD@LFr(59!<q0AJS4*b<r2DkuCB_pPhnOTTiYb$}JFR&?>%^SL=s>_7+#mFcQ
z5aXy+!4YH-WF6A-gn$;Z(Q$oqYwzn9BdN9HV<^CsxYCG}R3vc_DUuc%4<uuZ2?`#*
zBLD_%B1bG6Nww%;{Q3o7vvIU==()>7QIl)C?xNLu&sc+(S3$8{3%JqO03J`60O+5w
zayKMbjT?)Wc^WUG@F`DsC75aP65B&XGpHs7W6TZCfXE`P?!#_#qkq2Q$HI7B?ud^7
zseNIgsoF?X8coN|ag*)M^1IUB31PrO8jLNCqsF>;W*!28u+sV!f4R+ByV$mIQ9OFD
zGiVkt5kl6@E;fg|dnj5p5VxhH1;JA*2YSu+4gts&XI{i)VMonVJo&Q2l*VPA;ry#1
z)t|SK0B7w{UEdr2%(t8L!82{Y$nJHoD~L7j_A+<BR{s}p00c~vWmrZIWe%q>;Vl6O
zmU;P2drjfykU{VK9g&KvTKn>_Vzvj5Aw4<eKZ+KYGDr)+qZsi2RVyz9m>Y5Zy)m<g
zt*xDPEk%$gPmS1zTCOOA9TP@>X3nAhe*f6mT;Yol{;hA76`z7Kb?<w=ew$kC?NytA
z4L@jHEJDBwho#idEb11SGY7zY>NHdahGUkk+1SW3`vd#ePk7e|B0^_!)^ZECpKBjQ
zltEC>J@(BgBlSU)QorOj1ZznEMt>p=PctGBI<Dko?ZXSJ12PT3o9v&J_X${kRB<R_
zf>Dm`_C91Do1-n*p?)#9heI1hV`PcAheM0^-i*5@cE<zod`An%fYmU~1A*Eh(jsKI
zsy=gqrwOIleVJQa${7J{pqNyKyS)_-^z&P7lSUVs9h`YW<Hy6nnJn((L#Tj0faY1;
z_Ejq3Up*tv&-q+G^8+dUBj=57!@Mov^G-xWvd^h3FHaBPQrYJ&!GgZe5b%B~%6Z?@
zQ+%4cuLcc}mj3hl|NJrH#2NSS$hifJw$Jp7GuPez@mj)`kDVi^;5Vo008n8EYo0t+
z60<*4ldN^h0q`7k$IC(WcY>11j7UsH97DTz#)r7r>>mOFSL%5cb=|8oe4A3ad0I58
zpuwB3p)M(L{v@ePOILo9gM&joHQBE^lA*lQ6_XyD5#-uqoxZNsYxDHH`LQdFI6lGA
z`J3Y}$C%;XNLWF^(S9~p;}J-N5CAa3FE5YuaQ&Pv%zlm9IA_6Zhery-wDZ<+jTQfW
zoTf*QYby~}p?50Z#^m!x^T~bTgLL2Kzh7c+|2!Ukf8b3-9Osbg&fOE~Ot5x)MmS|O
zFWiF6i}<c(Pf^%1{5dZutAb%&1-bcM?Q*W`Pn0PNk-l!dv6t+-J-;7x*0X}F?2G!2
zXCz!kQ`UR`>Xu`+P`5Vu%s?jX>1#3b%WXD=;VST5Vq48(dRH5eeI(+`DQdZfkmCcM
z*Ie~UIITx~g*XtprI$gr#0cY&caMc9L$W_v%R#(ja~+$6ogMj)Mfc}Jt0BoyHmDGV
zJ0H`o|FlC{N?JAy3XpvjYsmwm($YQmHijab`<L;8j1}IXri>=>@THaPE--+%zK&Jd
zGdN_UUB=b>)xcwvE-cmtJ&RD@hNAzoY5q=NV2ry;Vb{%6E(bxF<P;mJtPI8B`2omv
z{IcB4>2Wil)4cplj4utf>8)9bss7`b*XT3z!;LFw7tbrYu&{8}>!wUAue247MM-I;
zg{dz5elzg3*Dl(-+qPqy;{A{>Ur6|Orewf}M&{pFz3b?}2keo$`w`Q#TGMH1v>JWc
zR;hR$hLQ2-yfYNN?#Dvcb*yRe)MrtL%Dn7i<5E4N>W@BNAWiCSS%4--a&($Ln2WC1
z;bM>yY}r*ouMi4w<H7@~SYq%hFK*!d`QPZyU$wlCu^2C{vCUb)RKoc7HqvpE>m@S~
zOB_C@b*!2tX?O%6t%yd%*)GyLSd<b5Mur0;qx~_$b0oPrS;B1We&!3TI{ZVp^ETA5
zGLyNZnu&7f7^Valx74d2Dj4Z{4k-I<De1tkvCVY^d0B{z#Xmi6F~eS1N3z#RS1?t7
zgQLE#cV6X_Ol16k)=8^-!vZtjqK<}+j;_;VZT`OT^<$n)G8Oi4^$ry;u(T#}s~zHx
z%k#rT?s|rRIfleZ?EKDAXpyt&@?Lxn4hROLQGxQbl~{xS?zPtdugG_+Bf>Uk!rh#~
zJqZ(C-RSCA`?U)488-az3%KQ1awg;@G@A54Tl<K{93vZz-5gwUCYl2l)Nzygxf4+`
zE3bB%Bl8mG!WL-5S=qbeGZK^kkL}i8O_&kSFyAID<#2W;Z;Hd_+b5F}ak}%a@Tj~f
zd<2t4us;sx&bg1<W!ARuWSmfs97#;Lfo5QNUXa!Kc$gYrY>0;0*-=9M>O6Mm2Cl&t
z6D^Gs<>F-a#)k0+%0;au&bn#2X4&SC$CltYYEap+F$kch_3Q5^n=aap_!jP+ZJ!U{
z?{R=_y<ETz_yZC;gU=Nzz{G&on?S*EP#PE@_5y2`g2Fcw&-2T}^<m~MR=LhBwy7eW
zknWtFvtLUK4iN@MmX<|E2>9Z*!#1si($yQQ6DFlPG|OR5Pc&0?TKruv&LSz#S`+8s
z-8>Q!bPgl*Vd`Otn05I7b+rL?TnXe}EQ5>6lJo_3M<kxe=H<G6Pp{1u<cmi)E9~=~
z=iP%F59Jc2AgvG_f?GKrjb>{^Z1F39bT6DgjuZ1Ns-BEk^lT;da`)I^H!S&r;bsY7
zclusokiceYa<YdhUX;E^*s4#)--rA2=g$QSO;=LKWGjC8#+vu^&CNLv+i-6<Idh(W
zH}Q%QzMo^Ja-{be0Jjt+udr~YN2_jI4}@uMPWUoP?)J@0^KV$CiBdV<ysxc$&w)Ge
z22!)#^#4aI&x;I_<k}`aUgOne<gmYtTUN%Dla4uae*d-7<%tzsU)VD*2A6<|2@XI-
zh)s&rMoNK@RnLNy78{J9$TZ*77Ry{Uuv{y$!hScq%Umn~*3U0mc~dnJ(6V)xJDKUJ
z4m4}0o$zpG006N5(h_7h@OX>YIWfWKC5_4?ftY%)R^m4)*!<A@hWNQEdYgw@@bXJu
z)s%eX2Tc!u$=L>oPhPoKS4c!2J4f%v1O2Jh87Y-`VE*XZemC@goE1J*M8L6o)^NEF
z;9CjHX{OpT?Zqu1p=`clYvb$Ldy|DN8g*65dYee^(bCC=a|lz11_5z!kC91KWENtT
zD~B4hHSA_SR_=fS#pOijJW7m_-m2eW|L_Q(Pg*Y~CgxhK)(W5n#a(VCTwx7QY23P_
zDy=b_!G46t?i^46VqNy2WZ`u!#ksVtQ#ib#CMIOQrE5QkQ&A1uKJ{D0rUPZ_v~;RH
z?ORg-G~!_cb(N8is&{Dn#&RB)w@B7MDs<CDwAGWB^^rkcOIcBT;<8IPOu=G<{SQR8
z2piCGMd+-)_^B;PCBu&;w?SfH7+%gM&4R~Fz1dNa&Tvga`~HSU`+%0?Qf@5B9oY77
zu0mjO$J-D9=WzI6parwc6cJ#s^aEWv1X}BSNlh|Y%`ru1YL_aid~-MUQ1CgwhoQ%I
z8xQ}RCHC&IDjMiRD@i<c`QR3zx(#i^Cy3K_%eKzJX>3YRo-d3p%51(rOaxE=yXha1
zq{Ym8yz;mz7^AbF^?>zoF3=dufy$o9a#fJU1$4@7(La7zOi4{6oGgXRma1ngNu<)*
zO$*jH%<wkVQR|wS5j+?&7l+zeEfBl`0)F{kox%O&m5!D__?pe6Y}pqUB_!-QEuo24
zof%AnZ}E&wSj^UZD57=6%4?nJVN_MdC9G1`<=%jx-fgF-c&jl7`{5Y_V{!x>2Zur#
zrGY~DAFQ6zFOD9-to{3g<N#0^k>F}Jy0L9e^s50h^vB+l|7r4bTL*v8rBirAxxS4}
z_<fh*|8<wihybF;J8@s`1NA)=3jWh&Re)VkMHagqm`nmAP8m~?A3@MiRd+9G$KWK$
zj!|C5-t+}UOx#Cqd?@DG&l%yv^(aW+M2P@2R)~p|)MV2k_IcxBt6FaFa_4YwA=^E3
za!_%ImRCz7$)+BQZOO!NVSj4(lf{;cWE!hliCl39)$qS75>5t?WM<1>UWT&|OTXwO
z;e#_O;Qjs&Iw@~@q3F2Yn4HJ(09Hj^y=#12mh}r@z4AY}Kym8L!*w!b5*r$Tly-Fr
z@#qZ3oX=O_gGG~u2StuuR`)?(%DH3NkRp$V{<;(Aba>Yu_3==gv|v;txo=|{%Sbsn
zv4t6oh7&T2K``g)q$HM`Uf(kqj|D|XJ515De@Aw)-g_&VdIRU-**v(6C}}T2Pp@mH
z2coZ^EuW2erK&$siE_^?Z6d{jP09Y^%ANoE9;jfu`bDc@iO$cV&{=dTkdUJ*@C{&S
z{Ixs%ZL=xLqgUGB1b#N!$Ub&#Mz&QhG4Efy6;uqX+f+^acgVX7Ggz5c3k7rA%xCxC
zxIyN$l2{>zjqT(~=w{ZSon7tfYGy%16}Pi(S)hM6k;Ts^TEO)Lbn!LQemBC#*;#=D
zwdH<W$2xL+9Q12M1fPcoCkSX$HlN=^MNN$?M;(PDeR`2Y?fh(!@RxMjYvr)}g59nb
zNdRQh(X+^zlh@PJyOKc0PktVn=o)WO-~c*l7&3WQYHCf34<c;7<V^m|$#w${7w0`6
zb@a{sl(qMLfLEo%;UdOVTbhb1PKTS;cWIm@A8w65+8$XYC`Pj_gkU1j(NXFCkrBSR
zGR?Kq)r{$F05l-@RDtDmH2;o=2XB61A<H`b=k|k>cA;>b&znnf(61%FP%*q;(#w(B
zIW3L25AJP#aX<lJj4-QIF|?J!@T;dgBi%18uLMVe1+4OFkWOInU&A=wATB%~Q2N|m
zMR)A|EWNZpgxm@JqbT;-_2E@h!_0#i=|v+9TF=J!`$T9057fAfYKwtw%zWSRJHGc^
z+CDmg)mbfNPSh6>b$b*|&giKZW4`rjoz|w?$xcJK1*$<=QQlKV#DJo~w$E~=1cTnW
zoP>WIhzaf01b^TO8HPhUYPobnzww005o`0gvRp(h1qB6wj1XD^V&%8Dp>EYq&aO&|
zCsdLM|BF>-!YmFgrSBOQ5$3<H<h<{vg8VmtK&Tom+*eQ_qEcmm!O6)b=+GeSmj=Dh
zPI@UP)4+MJI6a0(Ad7mEjussG(DdCsvHeo&H&~!*aCRA<q}=!K-T4>xLJFiNNz6Bx
zm(N!VV8H+g_I#@+%V=6t#>l62hdeGulh?3cgf!>u&!5t*sv4WUFB$eyp=EX7y?`5I
z=X!~6{ws2D+!JCND=+KzZ`N9QqPSITjx90LtqfqUTdyci(|H6l03ZWEM6R8Qf8SBe
zw|*dtH}xTLK=WT2mE4fHZy#@65~78~oc!-?q64B7(GD2#uWf8()vj1BIm%)Rcz>QE
zC1pXl%|co`-7K0eKMp2h5Xr{BzrXMQqxUzc{oVU-M<PzleBQ}+=?R^q^p$aPs&fg^
zK1=+U7U1*n@Nfv0qBxADqLseBW{BdsmFBJicaJJXogx@s&;3xbR_saog<ck`41frv
zq#sJI2@&X+T4l}Ib#-+O8G*93l&t+1S-mIu1-qe<)z_3?vv1#`1Q*n?Huk<CNDI+p
z&(TRUlqNzaN#fVdd7xB6^q5w^vT!S&e7>}RESOXK^|`wRD3}TeW$y*vOsl@aKJH<S
z`ga?Q%PD0RAcRO4z!H~##9KPi5L9!@)7r@~FxGSL7TSt`PlbDPM^m@VNy<(49i?UG
zJ6uGFTgi2Ca8)H5t!78rO6CSKUiwFK8Yd5Qi~vxG$TjKi6+O=bOwrfPy#yqoy`O+d
z=O?1?lc%7bv#MEdQK$cf95A`t*+EBObNMhB!)Qz7niDmp-QRCNcJhx8yXsk4qB*|4
z2xzp~N*sT3yN)aKHVrr-Y)lt_NK{yK@qB=>yO8~ssd|-|cS-eV`_6X`m{LjE{^QK}
zvv#uk_=|=9c8kLqLEAglJ)H>CV>@#Y-aj%FEs@6MjX~J=PWNfrn$GpX`D-}k0wOuy
z6)fd~tE-ChF%fS5;ciB_xJ372F=<q^cKv6e>g>tyHVky&Sk`GB$KBskb3*jRi_^K?
z;dyAam68$$U-tIUmzy1b(dwa1x3~o{s@HvL9-I#THdQMvk8iw7;Co5a!zoA}r!H1M
z867E$A4_=Oy#xFQ<jfQ}Gs7iGq~ZB3ESj6|XOAI=A5Yxx8%naq*bUih*l6xwjB6~W
z;C5*>kh%!6af2_RqVr5kb^sR-CH8}S4=xyID-n~D{DL*0PTc#sDP^%zr(l6ia2WZu
zKB%I?e#32NXL~Ry{XVK};l(d#qEMfsba%1ZnP>K0Pyvp}?QLT9?l%1b8{3`R19o>0
z>Q9#Gdm?7(Wf=$USYt7jdNgM<sZN~8^7qdJYA7am;up_Om$ps4F890V-)6*(+Mevt
zo~kyS!&|B3F#AdW|K)i*1L3cSVG<r5em1c7R^{nfF$|L#(wIhre}3NvKQS>jV0G3%
z!}wMjGKpTT=DBW%7F8{+Esw=BNmu?*>l5Rr0+dh~j|R$C^mB45YKfl#Znr0%KmZM+
z(K{)=TdUMx?m3UQp&Sv}+36Whmd?43BhN<cAlhDHg{3vofM4~|s&@rrrSVT%`@F!D
zXh6N*j!0)L9kC-l8%-*+Ig!0b|KoamUEk%g^k>5Bv82b-1cco)9-J%QY1^E(mzEal
zgYQ~tYm2UFp=Vmp%k!ho@ZP#wVp4j1Bw)J%2<-%lZId9=IUT`ORaKL|LMMhPI7gkW
z;MSj_zr9T*jJnZg{qD_EcJ8w4>M48sq<C(tdKWiY@7Bs)aH@>p{o15im@4zXEaZ^i
z_wI<p*(AL8#S4(Z1Vk!pPM2+m*ssS2Z1qUY_0UzQi&Rbs+lf=)a(aZ-*hyp9((G^t
z9zEckT50<P<U3QA`c865vQ-IPwY2FIdqMGlElAvQ5YXrjMzw8U;Inl8LI&>Hltl6N
ziJy1VQJhmKpm?}~rDb~O{qXgcgE+jp@{)~}f(tE%21a_0tUqMf&nf?^fr*HSpxHt)
zQdnIBP4da+5Va-W<a&(fj8h%}prCN~3WUnj^H^4^?G%rVb9u0THwq9Fq1!jwqH@24
znRzmi-B+L_aR8fVGKLTY+f@&x9V)8Sb6=*>65;&wQDt7xz8{)xt$@p9)|sDYL<-Mt
zbU<9}Fy=b``aGBB7!k8kyCl{Loz%F#WVyvzTTm2v4!7ke%9G(f4L|b>p+%d+J!ahV
zU1)(fn^lNK0c&6?H|64E>+{>2K(jhz#$4WyB(G0RI7@Y>NZ0#(_OVxS4*Z4WCM8GQ
z8KTCjnTl}faF6m=sD{$?tF)RCj)yEECK`=>d+ZY=994E#^H7YIi=s{;>OW4t9%?fx
z1(c-9caNtyM22BAA>!k!Z|N8E-<}rGMf-C(Amrxd4L+K-;K9F0rbJ?M$(8Ki^2`oA
z7FOXKgw~S)T~SZ%AxrFoV(NGc73C_mMhM_{VOum$b4cqJb5svIG}`(Jp}?<MWxsy9
z4JJDwbP$b;#je7)vKsD}wqr|nIq_$e5JL)^f`+zH-j!>naT3g*CB@%Ro~#$3;n09S
zbPxk4$ktmsJjN&5L`Lcn#>&ehQE9P)!F-%UJ{A*u$TcDB3DaBQ(PD)(hQSJh-is)3
z*nTP<8a)*;Fe3=Ob8a7U#9Uhg@VqnLgKp`;L0%2vOnVAC1z*<SX(*y(|4F`YTBP>o
zR2<rk*^zdzGF&&bRhM>vVCJKn+k^h)NVN+Ad5TD$`po&k43<sVj{hl|cc?vDr|sQW
zM*7N+Jb10#S}L`682q#4zTx4htx5C>u_1bvr?5vs0F?AWt}ES}U3A(V%t>G*iOHX;
zCF^yrx9xl=WQO4T1u&FZpgAOURcpF}#E>T?DDA}j{d;t*!<cpjik24c-TLFbINMip
z-Ir!-KVEye9QqNd^xkl+!M^w!>4q;M&}>8fKB`yMJ7aJZIkCwpDJkOsD+ZWRqpB_}
zoB?_@n5~_yjap^*jnfftJwR4s^U^6)@}PMTbF`41T(Q!(1Pb~f!6uEKpQ5IJ+UkdX
zyDfSJdqjdgu=SC;w8m<Nf6o$k9HsmU8s!?XD=>~(GDiWO!3lb?#xyv#%`0+wSwr&P
ztqxt}QaTL@OkZFBsZNhvtp@Tv{9<=br!fIL3AjY7HasOIB^3afc|JZNypw6e&0Ow7
z5+hk&hIV#$wl9Zj{EUDnOtIi}KB@GJ4QX$GQ&u+9!!_AHh9(yobNRM>wL*;5-}~Mb
z(QMWMRa>+l1@84pe>m;BmNk`8H%w=|>9)Aa$`%%(jj9YvhytQ~wO~5`z~H{TO@A@0
z;i3llst1fMf#=yHjKVgz?g-%JuATS*P`ncPM>~Mo^#^}d`Yz{;^gNJWf6R@D;7%iS
zle?ikElczQWMzaD_S5$Fl`c8k9>zU*4E2E9f&TxOYX;g|{T5-KUB7{etH*RKU32sB
zGR>TOLDMN#1_k7lCYyJ3GJ169Lt{4Q7jQY|6~QX1>*D>AK}4i5=`|<sXx-7){h!bI
zGpBCUo(OA-_Jge)4?@W!g;she`jhw6mShN#e_D=%muhh77#sOu^t}q`#eu;a^<=*o
z3<B+*u$vPJ$g<}-88rqo$%ju2^dFKZ;BKsGkrmu?9Nq#r^WK9z={JUw+gGiC#6%1-
z$2Yk)ztmY@m*G~NRZ4MH^Ru%-_XKhqLt)GsByd_Bq(>Ja5VHNd%K7}<098-k*B!@V
zRfYbg#l<h&LQ~-5dB$5rDL7ZL6@W(I*5)D10hH11{UkO3)pY@UmMJ$dV8Bx}TR5*>
z!)^P7mO(a{B~(|Jbu2Wdee!~o2jLky#*G06ijsGGc76_Ujrlevecj!i*;Y6W_Ud(B
zKpv7}@lK8%we_t#GPOE*Mp`<8mu3TaRFvFB|3MaW|EMX1&BL$OxuZiXS1Yk(<NPYo
zej^6EaLWOY{!SAXkL_)x?RlrJjC7B7d?Y`B3a@V-zYDS8c4yWgM{0DkWRXnzD0MiQ
zQ`x5R98D_Umk)?bnnxx(K^(LJI$FX5<CFc3hlR=yXyq~ufvLRk0PF?6;XU@8-29<F
z`R)001$5R7Jdh+Np!M`pY16H4UhV0@sH>~nSS~e!i-isJx_WysS041!y4hFNerKpJ
zP7&kbJm~H*-SW<+-)7v6`@w~^(fKsw{!;vPg9t#Rz<-X4YG6Ybw}V$4?F7ZFefpB}
zn49BgoAe%X>Y=PZTwJho^4W!c8?XK~KZQP9jY-6nh?{G*O3zHs7mz%4EN5+@(9)~^
zZy>&*$d}X(GnK%n7UUl%%U#n@ggQ^tQGBB%(=`qykB8bGoO_n%(A<R;llZFzNrf{`
znqjfRRBrQZFl^QkXbqe_#ydN^U43O0BO{A%gH;FNDevE)qT;#lt0exUtd!eZ(?VBL
za}YI1VuZewQ$yMl=vnDSoFy?55>iTIF<q8r^(~z0_=$U)W(6*SnBm8R839!HV2tKq
zcHIh@bE~L05)`pTrX{<FaN=;|oEgDim$^Ld626tmWq(U7THnIX+1Md*q?#*LSC3T*
zwj?gC?tbf_t*Q=_?;?j`H*F@*?qC8Mat3hN$Pw6V_;_~Dz0@8L_a^l-4guO++UqK{
z<FcgW=U$lP*5>+z4tcqzUfu)Y;}u9~@gHY-;Z-PbaUFZ;@bTX+EKH8fa&jGfWrl&V
z|F+3OLnECs^s+zR8eUT5K(tF0dsh$EKg+*6lEjD<@!I5kx(NuUG#cFC*5hgXn1vLS
z$)3U3@(-sAiMs)%v_IEDFUoOr>DcH`X;%5r8#FG`KC`B}Qk$cBv2|ExW;y}D5q)h>
zM_aLGz9BR99Z`@qAqzdCV}#U~t#&wcwdA-1ND`shmSkwpyz8Q_{t0nGh}~t0FJdeF
zee9YXdKy=*xuPe4cI-oS5Z3=vl^II_PoDT}rTP>y0vo35ZbD#PqjbDseQWQ{qJO9s
zLb>)B78<R@6fNt#ME0||ta9E+EBs7AtH}O<&5t?}#UjQ&8YcOp{3suM+&q&0-LR;f
z_Ks!olw=GHe2%tHeI|-Yc9>vDA(9gQ)wyt4^0^V3r}>uyDDwWMMpo;>1~eaLvkv_N
zE%B?RNQ%dzCWXEc-nF&OK^afBy&ktmWs}M=62BGNFfuka=ZwwIhX7IxLs{J0;9mo;
zg|3L%-iNZ6giz#&%2I5Z5J4zAI7rGN+NLGuHc(Tbk}*bL@u0>u{V=(A*b5R*E=N6%
z2U4FIT#m(Ui}ql(t{>9@H%erH9U^-m8~H*d{+W3ez}j96gG!{F6vOD_Y6l`>WbU5s
zLxFfg!5?J-t|5lc2NAs_lXzkastX@UNm1S1Io5SzJ)w9f<`hjVuL9np4&GZB8&jr9
z+5ME)tR!Q1LtPrs6_478Iq29d6i9p^Z|Pff#P0_NZW83u^{w~#)={kHc`+@^3j`{q
zM@?9MU~c@(5H+ldJd#tgL$!ORxQR#lRtyL%lIxy=P$|9o=4nMj9K*0*pyFOCG%Vs+
zokwf*E<)h)YO$kQH|fo&ywSGMM_Zr4NPbSH)AG}>;6a7nh7_&z;VA9A%aaDR`v}?}
zEG=&bu22N0jVCjqe3i~%O#9V1@dDcZANqp7MS6olZ+2lncieC7!`vA!X*FLP(E?g|
z{2eiDr05)Jg+-N!5D6v-#MpYut50SPbMMRBie;}Qlg!kXLK$JP%2Pj(W52XgODTO!
z9v<n%CB<7sg<p@3B;++EPHGe-M8#rjB4l8Jm_x$d6y|3n_#Uzg@%%XJn#r=&Ynp(S
zoDmpXr9ZOL`}Pq}1KF+m!cK0rkR%Kau5xD(N-#hFBhdH9ByAXFnHd)jk4{F^_$XUR
z$BB0EVf9(wi@0WUEZi|$s^K$UeUz7%=Sv=q{cMojA4Qm;)t3*q-OQOgk$2F`&Y_Gf
zmj*O1IOK(eA9o!lHja;p?Z(qM@FJd`p0ZZd(#!9*-2t6r)4VYNTh`3xvVOUM0x(gq
z@=G+Db%4PLS;_iYk%<?P&PqJ1=D<*^*9i>=P?7rEMYTXCRSti#k&^R|BpZi{9sqL4
zfIIGgyIdd#N_W>*$`L^Q`c$pSsxg3ndY~rIKh?rFx0UXld;7Jm%^{4W+R0?~0~(En
zJW{T^08m@b6gP=-@oA&WLWfU^KRQ`f*ejEfS<@|O)X3IU<cnBFVI{YAlRaz;%iT|o
zs{b&H2*)>ne`lwRzgVH``BZs8>T%c6J{j0~foeJkyP0&;A1)&>*!XF_c|wr8>>~>T
z6pTO*DG#~8&$LHYjQz|x*>7n9DNX018Z|P4D9LlQ!!44XTW7i06Gel-aj!T3)wZay
zKKw6eDor2cs>%B2lMsN3KDAt6)BeziuiF{ZS#EY!KV%~$IMJIqos^2L#VI*VSsd-U
z7)t}RGa?n%uY9GX8;>I924fyy%H}Q-v3ijKAWqg45>O!b<g#8fA{=Qa{~$Cukw3p*
z-<{$Aj?ISGJO$y7fZeqhT>TyyIjG~bC6|Aw+VbFV30s%Wna<)=t=pKw`VC8#sxk`7
zmVRfZ)ZL2(*}**fI-GT(KyP0r`*JDHr^~y~!<?0<Gik!t-)jS9><4>|a-ds)q4G_D
zc<%YY&lX@x*tni~SaEh`wVr@GR|P?!fc$Bv9lZI6C$U$n&3n^@#Gc*{ma=HNi&65}
zcXt^}LoGmnF2tEz67H9aONzMLpRQOkdYj|a6)av)rU82KgKo!aCt0c39Wj(~DItyr
zD0v=x6Ngg2aFKPia-Gp-p{y4GS?NyDP51PVZF?rS$TFGE3LubL#h6D+_j(~#`{9o9
zc!P&Ta4@T?7_`AAM46m`j`k=!UB;cOy~<*9`qQ)KbRIdoErn<j7G*{RYZ#F4h1Rw*
ztqE+O5X|w?wUrzlptML2LMx_EBtUJ7=syF#V-1Igtaevm2eXCYa@rmt)~%XU77NZm
zJdI2$89@X2O8b%ORE6=W*941q2Ld{elfk)0v(T|p!i(SSqyFZOH!nG^LBI)=ow&2b
zs&EcXCU$438d!fLAV*BArzO+AC|h|H^6c*;6!Zo}q+g|`K-_P7l4`NKpNaAAYUo|Y
zn*cDE?@_v?LT7@0f}%;JW?Q(S$S`UQXXyt}j~41|Dwl6f)6lz9sm%m*eWm&8u_>}_
zjt*8G$fV1nl7y#e7IS1aC@dNoV}5t;UTo86PI2<%`NQ|FAF}$}K?IE|B(8@}U}c(Z
z_!r(oiv}VX=6b^ce=S-qSdgo2QqKlS@1<XQ(T5l6OFh{si`c7ew%E(vuBarEm3Gx=
z+GN8`z<I{@<j6HsAljCQ46FD!MGxsEUmo$B<`6(kxty(KR!BuZ@-j!9rVrY)8O{kV
znX9^fZjbx5l(oQMp&9SRw6$hU*kmj`kV>eiy8|@?1B+5Ws1;4Cq<D>!5a)LeR9-cw
zU{cP=e<Sc1AXjI!Q_c&_a-a^E(lIx}H~)^eNk6%!V?{16-j9V!F|j{DPzz=WmM;|?
zn?vy9Bi;<PrEWp*+x&3pkcym?;i{C%#W2qgRVWkua{V<8YD%;<P|1L!#o*)pL;#kp
zjHIM*b+tX6J2~{@Kr|~WJ6r#hgb71mLZx=_2#mIOX+Cq8cnq=o#>R#mK*i|Q#jzHE
zaFBJf@Nl3B!%sTUCnd=L62r3YqsjHoSo#p~__e9ufnpyWE9Nn<c|KqVhGRz#Ad6&=
zC6}Ai;|%>q*3-!UnxztY{`s~D)?}&7PoCjfRVw}8BaatY$l{%tDWdce-kV~eOtJj_
z%%Jc|Y|0i@jW!bq3G{}X%odOxTVk8*o12>C79}CVvf@Q=L3sqr(|jN~Ji$}h9ox5u
zlqaeT?XO%f;c6wIp%%h6`(!dzd65Bwe)+JK278vzua*3k4~)Ptrulp4&yYUk3dUdI
z()M96p~XMZ(easyQvld{$t-TG_w+{LH)+js!vOT5Xn^j>V0bHGZz?XOiRvE|)Me5e
zhQZ*VBs;MQjPrG#>swe5dD+J1b6pKhPV!evHK)aD_67=9FjKomGaoQ8eD;h6CPs=J
zXVsFELZ=ZH7p)BSz_AoA>05AXDpgJIJ!)$e@La2Us<2sLr~76nd%s6(E{RT0I&c?z
zZCF`a=1yv<fnM*srC%LQz|~ahsG?T&4T{&68ZwEf9?*Sa3d{^(JT1?2gZr(}rQr^V
zTCX}kUaA%5<<%X8Qsuxo6<mJTV#v2I?a*Qr@=!nei}V<eZ=Wev?isVRyq+#nx-*K}
zPzm`WB|h>cRAGNV0HqJLba(3@-L9x$G=!ani3!nq$v+VHeZ%$U<|ZQgJPsV@bWpD0
zd3!)eRdvybgf?$e!wi_EgU3d<DdNIHoh2mz5g<iGz?;SE8yg4tg6J&WXl6*+A0Ho$
zS1V`Cmng5C8vpAtyhYnJ6BU*0+!=Y@m@VZnnQun`hWJq)WeOO+p5i$=P~^$XnXA&x
zUX%dH?4Edg_q^y_rk;kRB<z*@oJRS+>!-gO@8+*y?2Z;efV^jpJmgVmtLHBrC?^7#
zg{38M(Qts47l1wxlUr_%r_^(f+;C@=<;*i;RB<@!(6COBlsA@sjJ*P6lw6V6$%&QA
zey+5rr1+Qeax@Q*79oE+p}-=_hv7nL+FK>qUkYJ9EIc3zrlX_dgJzQx-{CB^1XJK?
zx;$cR6YwspT87((0(kxc8;~Q|vNMTx@ZbC3-<7z}ZhHHFGH#Tu7^jyqnMcYl`xmHS
z5Z2u#iBs>#OE5lAzwm8}nJ}~|yIprHNB8O9U#!~fj%tSY9x&t!BUi{aApQz!y2@C%
z)7$#w!D#T_2yBGU$S6+u^71(wG0zTpa#t-bIf@ezxKXjbZ}Ni+P~v^U|1R@@t12J^
zQR0#Ua#eLzemME{BTL97C&dBTt5g~_ieCZRQesM%KZ2RR#b%uVh&9hSXZ>%Uj!B{^
zFS1lA0Kq5huPM{tlch4|An`ZekS4QWfa%@Y^)(+bml{r3#>I7zrMU#eU6j7X!=q)q
zu+Es+@p>2*GoRdknTU-H%Ph0!KD|Xa9^$`+%|$!ExbSzUc6M=_jn!3f-+C0G#+^`2
zy9EY5zlY6i??#64y7FjOx!(7KX$gX)kZcGwA2b{NQ$&=(`;qer$?0S<bXsx0Hw{|T
ztayJP$zrt?%XmyvmNLKS@_*#KO3J~OH#bffBO913H)w@$;wUtenZJJ*_5I(B9xZ>y
zmcj!FAi_3H^Rhd5FsnoWvHU4A7a$&VW63nST|Sn=7*BJH5Iz+Usgi>G`^TJT!a<mh
z!8DdR;F+l1y^yB@vv53(S`unvN^Y&<q+>|Gc`iV)p#G21)Xs{2=^G^nF$?BD0VZBH
z<bTbOr`7)7BH*jR{~!YA$S@UcH30HYr8rS_AQ^*lFkVPg86bJ_><*UZRpQ@Oi5Cl`
z15#h^#?gUWneC=<hnBdS?`Z2U6T2Zw#M}=h(S7tjMUw548lG0Kld~Uiap6Z+2`Qzp
zZvUD{{{yT&0fU8ubF>4C&TM4;W{TYsq487b*S|{NT|q24ea@!D(>zse^&Wf_qxIz0
zEGIVgLOe;I1O}<)V((&_p-+I$B!dy8*+&D)e-CTz7x7nF72oXZVbNrd2ozy%iAmp6
zgO3r>qO|!dT;?~M=It(1?z%<guaYE~St$-GrOQbs??U6tbmmTE&x0dnz7<ma&G`8n
zVd<eLWMr+sJO|Z#ZN`P*&PY9!DAe{2F1XzfG6@PUPYu-rIllg>+@Sy)FqF>I=v8H&
zny%eS%kXr0>hz1|%4NdgazcU%78AEzOc}=%4I&~G$kqjhkb;AR{RYLz00f6@-8hhj
zq`S8#`*aEKOIBO`KhJ`Hiz^K!))HC$XoYw>vD#k4Zf9S8wj@VVa15KMo@<UdT(Gsn
z(t`^b&_XtgX0W1?<4Kj>c27X5wCbR{dL_F$2uZh(QI!Tphq@ZgNzYj|c_1tm)d*&_
zxPnujI%_G)$SJ6ySdjHA&UY}DrNaQfg9fjMBethzk67u=>}-9T%UK)`E>D`1pY9p*
zeMLO88=IMg{)ERTnuWs^i2CP1ZMt;<WEk=eF|TaxCMn(=twcI@;QwNZCTA0Y=DIw8
zj88+OxtHA$mD6RfK;;y#*e?LuPV(mDvFtM}AV}`a8+rY}uwMR+8gj+EK&2@UZtD%~
z(F}yaQf61*w|LTL`atYqUESU8+R>4r8O79}c3TNAuJ__sN0}bp0G#~cWI1A7)!WJn
zzBeq@Hz9!(bKm7J(KB!IZj7RMBMI@q;Zho)<w9Vm<`rx){d$%NJ)k?%iY>O}1@*%`
zO!>h;)0K#&uOSJ!ne$NZGVXQDQsaMXeFNJWY{A>wUJyJM^9Z%h&A%e5GslGIZWr{-
z&qJmICjLFE(me&bel|Ou#Qv%9Xdj63bM)3HV*$MhO2f<`hj=A69ZK?nRJu{ZbR!xp
z9Bjz7lAyrakmh;MR~cPX)eD+w03_<Vv(2WXG=Xk(KBQt%pi`>T)1;9V&-H%gMrUwy
zA(u~b-re2SpF4T(AO9q;Xg|_JY&dbE{^JxWRk=({KvB`bmXC?r`9yGSa=X}!$l;LP
za|gRf$-Yx&=mUYtgF!-qD8qsW<CbUhtCsgl%mJMlz+4do8ASKKxS5c1PXl%muNGRN
zz-(m?hoi+r{>hW+zqA0mNt~`op;#<T_B(^a?(|lKl7~t`yWxoy2Q!cp0xy6qX9G3d
z#oK6h=>m7Jq9^?Wb<Mob*brBzp{ri6$bdhB__4?TBBI|DSxel4jgSN|D+F5X7Iz4-
z#D`p(ackGc@RQ}tT91ss*};i2sW0;tR<m>3odXlN`XnQ9L$S`=8pEDc9Bp{2t_=mJ
z1<h<wx$X(hW)LU2-7tNY5G;5elQ|6i0ZoJ(ND%-`o)TdV9W7w>|0sJ4pgOi~Yd8TC
zLa-pgB|$>)5ZobHfZ!f1xV!7d-8HzoySux)yTitP^EKz(bMHCt-S=1hRb5o?UCHk5
zwN|e+*BE2Y;kBl_j`qXkJl+`&UgD%X`bG!<!@GOkO!c>=m6sKyN!d8DSCW<y*>G^N
z)@@F*cXt*VNi4Fi5*JklA-VwJM!-`O%cj){PBXW*cJqr#VuB@;Nb=#2@SiS<*IM_I
z!eJead8`F&J_&?i1S~*L^zwxd(2sWzWV6eIB8HlLG!dIp{nOA|fYQTZ$n_OQ6U=B%
zDS4N5@ovInJHQdBs|B9R;oGG6Y{D}-XlC)yX<&UkiL?nmK$(57$|lMjOKy-f;kmsI
zD8Rmr^p2rv=o$tjbJlACsd!uU1NH0M^3X9D7_}~BP=KZrBg8U*Dl0vNJ!|{-`4AL8
zcd-5uw|Oa6#ludQd1(#i<!%q%jqz-3t?lFMW$YUa0G8Is!{y*|yui}xcJ&5q21rP<
zd9trZrdp!nBg2aO799dDu2fh!I1S;+ToR_Ky{OR*8qLSP9<rOinVx3Cnr%T|cG;mW
zQ~nA!%4v5ti9K1k7Z4UUq&WyEiZ*B14=-3NO-ZLn+1^9aWS>>=AC_@$4kO#_>+VI<
zW0@*%Y`P2q+8;VjX>NC62N3~aa&C_opIJ*QOq#cIbrmfbRs)le8XGd#hdl+Xgx?=a
zoiM}awf7<%%1w>m%y|GcE9@N{G&lVuyp!Tp(CR#hq5;9Y2IkUv&PZZU=V?ZA_VyP^
zry)S{9&T~LwD^RJ#79Z5z2fNcP-(1<*8&ab;stc2EDW{ZXzAg$DqdcPLm-Hq^b&ch
zI82h$nB}L0z?9GAeAo92=od9_OH<8%rWyUE8xSE%y#uY23LDKrgcFcbcUQ?9s@E&3
z@fq>tSi8navHgMq+)HYFzl_e#DzbP`&d(Fl;(1kgBMQE<7Lu*EJeIaZ70Ujk=?8*s
zRLOaX#MS5yja&>L8Cm}IU2Hf7Gxsw=DIEWh2vkDxxL}J@)|$J87IDcJ|J(zf)OsRf
zr^VD#hDp!K;bvOl2qcSWcaRN^tWs@qguXDmxejdUs)Ju+ao()mrRW{;EeXYxFH-Rd
zyDa#nrR80cJs5>3<K(ROi<|1kwAv2`@-V@hzD!&SmV4^(4TXbcU`=CwAhm&tX!r8s
zM}X+V;4mBdt#X3|CO$!apHAM2J^~CKoz^@*1NdBEGNVU?sZhNIrL4?C5i;>@viJze
zviK7jX7=%CgQU&RiJS*UX-4B-bnVm2P3m&vMf;mID>LZ;Eg$I8o0l)VH<p2Wb;Rz4
z&u*8Ytl*t%z_{q*(&+6{a^Z|U1RWp1W>H;L7A{d|b8mV9S)nAtaoREitwW%v$T>El
zUjV7&@T!0%9su(1;bq3+?eD)8u#o`BNJkowav3`HPnchux&GgOL~x-|$`@l?PXbx#
zboQg{HxOU-&RF=bN$7h|E7PhhAP5nF5(km12P;^52=Xs_H#mvK)s9>IjTAj5Rr0zG
zSegD{{luGQw!HY^aM|ibQ~<yH>x&c5l25@emyiM0wOltdGh1^y@zsad6D<UxoN2Hq
zuBYXVDHLmKv1O|btm{KwtCzR}DW7Keh5IJZ>X}#U&s8l_`i*mTSKA0fTTjt)WD&z_
zwz$MGY|xO&NJ=<g5yOgNHOzm!4zE<DQT#?qMubtbL`Kx^^mbj(4AwH*sv;r&x1W;-
z-lKr1iZh4lQZo?y4!Jg?<B#n8HCX?>A$bl$)U=^=2(X>cw@nbv4Bwnr<4Y|pmx)x6
z!uFkjOudSV80&2f6bz;#!s3vG#WA=Hmf+Q{XxicKH@v^)997*2>B~)^E$vTYGRcsD
z{~#xoS=);<Uo|bHBL1v%Y#kniq7QlU?WBUk8>A9N?YZ>o`93nt@76#|kVV?j-T96G
z{e-Ty=Obg_;yvJ`#P6j!6UzqYt8ntv^p>8UUeeKRcbAOFvRa<nvXp>k45<q#fGQg~
zdY^`-E8XA3*mzZ521iQFK|@F9sf{>YB;3F96i)yKpnZb?fdk+UD9WGbI9Wt&odZyH
zKK>hJ8#z2BHIb2%EdV}RS8Xq@A$LF`lv`9(G`c2VAxNhj{Yi@DcIBXHG>=c&8^d4<
zAkr$a1KQEc9&}f($2d~q@)hi2?D95DO-(-?R@Bs>C8XquSdEtP;iAm_c<a*0X};CZ
z_>SJjJFzZvpl?h{#ZJyqE*SK{@{{E?NR>;31?<w;#1o#OH{uhhzteP&lxCJPGg@py
zN#{IMED4n8gECq8KBB|c*Cw$?9)J-*RkEFVw==u&xXeEg^D=j5$5UOQm{(gHeU|`n
z?uMDoZr^P%$4r31RF;t4_BdR~Pod-(3KrG?y=vVV0Fpg2JgI#U93>d8_Z}&x3+2Qs
z=r1ymC0krMFI+d?56080_ZnD=q3?uG9UU5<KCYXAJId899`6uQx_*oeXSCel;m_BE
z`{!|N=X_teN!5BdG|8>H7Uh8GGoI<w*GUHmb7D>|enIbMH2ydT!ndHW=}3>HrDDJR
z9Bf^ngg-{tWffUtHiHACdV6?|zu@{m0xuC#$?W0P$w`Kw6b9&t>=4hA61%)e1zY#9
z7Q6N7B&XkO8Zbe@K@`Dtm|Dc%)C52Yh2$E~z{P4P$uLze=fk%Pi-q`Mzq1Z&qmU(~
zPRn9LqW79malMg_`$KTLG{OzWKMx8S2&W>yx5E`uO!!S65Upr7UYqvt-cf|n{A5qp
zysoYeaL+aevIL1!m54_vpJcU5s$+8{JwtSda0Vv6NRoWrI>`D)j@0{6D34rw3uJcj
zE!(3*ak|((b1@seXm{<Sjbj8~m95E^b17+&j8rI-4ZvH6@s;S)(a8~tQAXO?75E=7
zv8BlfZPBt_Y^h1C&Dq%&`$VB{^;*q6=vV|vd`CCrNU^Lb{ero;vA)iuzAZ_kVn!=*
zD|@+ri@s19j5nQ+*T&#CF5VeanwN4tQS(Y$YRtf3FEzzIYTRpF6^|R`({@#PIpD&U
zwCEE-F;l$6)8sgAO+q4*BYt{8^~`FTvpcbei)WCi##cv1Ca1TPSHVSx94(|9L<(jh
zF;_;ruDzrG1cQ`O?@8nZKVG4sttYjw*pEy#fMUF_0FB*499F%jLZ@dwnSoV1Ejdj3
zqn{jPrL<#C1Jt4Y2e|Op2XNxM&uDsJ0QxVpoJy&6I1lNK76}gz(7CS~_zn6+8&UC<
zE@$V!zRGpZv^$eUL22sxkllm0r~QlTg(QoD3_iA^yp=&g&kXPW2ZyL+1Un-q{wxuE
z%}n1jC|qo;bqzxg6_X&6S4i9P>x+ZEZ{}_t&YE*8*Gp`KvPs+L#$QY2N%s_APuyyI
zBK&e2TvVAOSD`8tc>I%tT+S2nPOJnHiB3*z+LazoK<wt5yTWUmGO|Xdx^Md@eqsn<
zh&@bYmWk{^iA;!%#ce(`fu3IC+%ms&up{K~qcBk{gDf_-8_5(_eD9dI0j&Yc*?R-P
zSmd&&WT1t1x;Wo`oJ>+`5kZ{z`1NZEs{xD|!(WP)SJ(m7%Vk=~R8&;pwtMIRWcdlr
z2W$Ge!$M<8oR<_=5=m=OR=@E!SXt{n9Lq9)`SLF0vA0*qvM9<nRWP`nRwS1XBbpjh
zI@jLG>EqXY^TuzOyR4so_MVDn@!eMga=`I(8Oo3x+R^HV$CO5YqToP`DktXrx=#X^
zqYfe>6h5wZuQ)h4zvxcx)Vi=k0hvX+*H`y9rVwKkgCaw`Dk+gS6b=@9rB8)uZ^tXb
zthfof8R3(b0f;@!fdWd`wYb!=$wD}vCuFOUWDk?`>&Jd&v5<%PDx<#m&7PhyI-q_7
z>9}2O{d8E3)xV(kf2=ydhtEkoeQF8gJ^iE@w6{tuXs!?o_t{SWGwXgX5(b?a(C>)@
zM5=>FCLqn1l2Ad3l1xIqm3!f8y@=VVZE+BRPGUXmx9l#1n22~=<gEP~0<rJgDf0O8
zMiDV1r*I#Qjj9PEZ=eD)?PswgU9Hf_(37{m;JzM|)Jjw_)lBhd!Qo>dp{T9OtEV>n
zU9exKVpf^;*>%zRH?!X0i7(7dyoi)ryE1mTu!kUXvEBE$v#e8IWoaL$Rao73FVKM$
z)<Cg+(@z+nu7+7{L!7g7_^^aXZ)<=4Oyk+J5vJ&IlljVT`T*a%NJJLFm1VLJL$n@|
zXo-F#N=^doqG|WD_Kqgg@T(u15Nk|@el69nlM_t_lj(gGNQ)qj!CNTDE8g#R{%ZX$
zgm6yv@ccY9a1xOcsOx!*{^)f4KpNiexyeY4?$Bg8^|KHjB0BNWk~Kg(JNHPnf$wAZ
zcYZGxR_MIoW5oVCQQSbOGzLQ1pEai5OHS9Gczys=xh6ZS1jsFj?ig-!1kSVHz_S<l
z=Z4WSFtk!O)oa}kb81>~8Ir(W#8vc<<WhKRW11w_7ywlpTsJVPO;@r+3OkuhO8kq8
z5VKu4QLJ`;pdne(ThUA6L`JtjBn^Ke6AMu)T7!M^YUsn%-8QGlH1tj02HL7w-hb^l
zCeqOOJbtATStCX2axJ&HD9Xbt7?PV~%8I<;P93dHquxw$=HlcaVpT<HOTc0d(;*nr
z(+nM-6(of>VDl%wmpczL{eX=iBHWX8_HOht9*@Hs24Kl19Y0>!oi*MDhJ{Nx8s?|>
z+ayI^g(+U%$EWWzuz^r+^kF=_t%*_(9y2DiIsAa4k(dEI0QeG!N<0&GC{tNNk(k0p
zY_s@K<-qQ-P4hm5&{d6^+2z*k;LAqBi2(X~@}rQzV=|Ids--uZ?A;xckm8^!!a@Va
zX<UEFTB!c?`&X}Sf1B&0HFM(z0LiNM9m+UGM;ns($J0o^9h@n3lV<}AB{CfQU^;Tb
zL&~u8zMahdzPBH!5uiKxob$zmpP9oNA0v608gF9b=M|5(AyhZstlM>UN#_VA5)rj>
zyh7z~DDT&DW6|ZN{hS9I8=j`L*McdogslgAlxOItd5X(UJ0=|d!F)BX%QvSv?*mkE
zrruwU8J$-EHeSfwkbn?XHD2H0lGWJvpbsrP^=)#1d|iJoJE0dvG><fwYjXodGua*b
zu6=a$-AN;}tTXxZ1~XeihACG$XRx=;bNP|mNe_y^#^&<L?8=4gW0?1$SJ*q$>C(5K
zUlrk+D!Ry(Ru#z^sjC;s2G%weRYMhBJudvT%kq;fD<^0Fd>>KjMGCL{?G5n%v>&;5
zkmv_VB9-_s&YDK(A;%}nR>z#z=MC7t^m@Zx=>no(Y}>6L93brT+qNZNV*>-N5@I8h
z$i=AExHRqAe2_)ET)5-BrL;^tyD0O}@$f1ecJt@%oX7U(RHMJDM_MF1T^T$a1nT@|
zxs|v1oUn=GdNftnuR(jiImF!(te4^-9cy<R+wwcu=gx7_wnqY7k-}YsS0!T>ukBh+
zi8_(9<Tau97J(?oroU*$atpGj{v^Fs+4SU|lJ{tF?GpOgw{+KEOYtg*LyP=+II-xs
z=43W2Juc;TXv6U2@gY`%*y0ydV-q9nxxsblOVOl{@ghzmnbE)7j#f#;2rPtm!dWCE
z-wK`)+~4S@KO%Z5FL^c6LB}Fv5Sg{&sW|Jrx@*4wfVX%l9i_51h9h&?@5#b=huj+o
z!4DvSyyLRV={Oe@bG14`SEo@8@g=M$JR=o8kXFiaXo-yaN=3p01sqMDZkcZ)%RwLv
ziUI~$zn^Da4kxJ-j0KgKar&2=3S2o7Mo0lwn@RyeFduq%RBof=oRO+4XW4S(0f!2l
z`)3<ICC!32hBie@6+fGjTYID-Q5DH<wuFiepu!Y?oaakKyYU5PJqgkCeh0EhuOVbW
zaa{!iBFIHI<?Hc?Pv3|<C~0QaFAZvJ6yyEiNw>gf7jBtwVSbIv@+9pFiRDGac2#&J
zA~O?nubNFw&h6C-i@v!v<cN@`MbES(7c^%|i`KF##R_kJ6C=e@jvt$uzzivB;<-ap
zl%l1K-8sxdGOPGDL?d-u>af=SsxmfqW^(n6`{eHK^^f1y@Q@1U@Uh06?286bbp`Vp
zo1>wjq38V_lqZxmImty2s$La`sIccRlUw64)XlBrR#7XEQFJ~(t$Kbge@g0yt<oA<
zrK{wJy~d}uoX=dKm$ZWp-O^LTu|@{G8+C74VDDcH%Rgik7QP<Zsxsd{fEJQafNmh=
z?Bt{;Y-3iZ^<g5cXl|7tbb6~doCtgY8p}I@yJIR9haxe5L{Y4_Cja&gVd9Nad4CYy
z214hi7Ep-{C&9eD6us{>zQYjFtFSgNui^w#LjK2;iNMy39sLOiYa&MsP?k7-(P(Gs
zrTs1#gyn;6w>)if)SQf1u@lz_UgrS90!qDN=f0!$b&vi4k-;SP9+L75q0o&j1&G_d
z-g0owc1tj(nmtA!CT&~dPKtnY<6ecKagtSEgwAZW3EB9#Oqt07Qq{G52?T=>bdh}A
zh^8fYjltDDJ<N0uH(LQZOi3aRdjWR=1C@NotH^|v7#;m8$KiZ?sDgKfhm?W>)o#gw
zQg@jd`sDE(jfA8#y+w_t$7}W7AWpcux^|H7Bzykk<TQCtXhlV2Kk~fP##NL>B7V~9
z(L9r-xKYbR9qWO>z5)9S`}*2=>uE>8dUO)mkpe@mNo8?$V}Chqq@!bLX%m(v5TQc)
zJ6B@B#;BsUrW2pZqbob)7DDzJuoh?lJ-tYC;RClmURRPWA1yR^G!#izjubTI>PxUU
z|G<j)ipBhc;i0FQ)V817)VZ-~ZBx50@&c56-xLrr*Jy(qL-qK!<>r>k%looMyS_Nw
z!rUz*l>OIMtVIX`jrm)!m#650CoAd6S)nhX8(#Zty<Y|g{rLyTL5ps?;#>devqrL)
zs2^U6!fEU2@g-a@N#lnH`sq8(=2Q;c%Q@&!fAe5y0hj9jaGCQF9HNc9Sa4KUZ3ag_
zVG^(>dmb&=6+B7kY6o@Zh7+f99;DUK?d@OApa1ygai3aQh&K@95}cUG(OVMrNgOW}
zY~JA+t6U=GYC_iX7Fg?vhm$A;g@xg=#hXxsg*{jI=9s_&>MPT%j}H%{<4}c)b+3UU
zOCBvLgxO*#Z&^ocnnn`8nwhO-jQqX~A^tT2*<+z(L4^zBvHP^TzIe4VHa)AXqJnVH
z&NUQ7!%YpDz@??k6Sb)VTQNU!>(Y0WCBQhMyYu?P?RVrkw?0nMf&wNdqX=}kgO41c
z=#LxU&&>&;V59hy#JCiXi&;0xE%iX%zVfR=nP2L0{Q2#9t|Ivb|56x^(e*)5n~*i2
zv(vtp``2;2MMEF-FOxW5wivY1oj3ra%*f8hXlvuuH#TnF>|@>?cKo8_j(5Wjh-(Ue
zRtX+Kvr^p@W7{cS97rnfpu=8f3ZsG7dg6cO+<39PPc!Wo-#ego9<=z?VghqG$6Y=2
zof`Fn`||hJvoJ>ZJz$)!Wi)nR)vto4jK&~K7>3e8Fpf;_TrM8wBTIIxJKRn%1_pdo
zcjogI3O^3m<6D0Rh3~(sX*j7*3Rw;D894p!1_K<9R6uq(lGa!{?dd+HRd{lY&n^7&
zahXw_8bZxwoUEMOT2`!jhl~VQh>#w)hXZYk=@{=&yU8i0sFaMdr#JjEzo{u#vr<_<
zQR3Agx$o2xhYOA?^Nv#E{qcS80K3LmVv~2Mz?aY3j4ze1L#NQB++n__&Y<pwF`yLf
zEnUyuvz#5OMB}VSR~3LG89E}@l?N6aR~9DtXZwR4|6CdV{Hp+WalwFM`EG9~g<9Uh
znlyiKe0+4&t!Dd4&R<ASP%%Gyb8~cIa1dJl2{peIOoc(?3_C_QwhxvS{e<`yf#2~b
z#rnEtSlGKzcQ`n}qo|T!u21E}Sv&lSLsa=@_U?y@s_N8vq%2`s8Qq)EH$p#tL<x*Y
zU+FvENnRW+VEX$*hqI9gB*AHj&n2^JrDuHkq{VP|2`}L6OeGx=NyXM!TmweAsy-xi
zx;EBpe$u~=EwY+#@0otoDk-XN<X&LUp?0pcIuij_As(Sj|6OqJF9)nO$jdOkjm`Hc
z??#nVkY~jH7+ilWhrmP6B=X2l^A@UAU_?jD$q&h?s(MCKwsbAK#L4gZgS*8N%1j>x
z3ogY|$Xo9a6D;;O$pdY=+LB^o@;AH4$y)d;vw`RH^5z^F$Kbl+Kx2K77<LMy>kb|&
zy^*@Rzu!X&#QjQwZE0puW+Tp;D9#=_Ye=C`+Dr{}Sm9jEBeCPv;oPwE(-@b6@=m39
zDCfP<Vbzqp@^VUpN2sm1ny?#;G1=-Ukr08MISLtg{jp(fW6fP%_Xm&2ZWZf`y>G&-
zjU1e-$J_lWn|5IOP4oZs=BV-;D%E=Qj~}NAEfeXw!EREwiqs`O-JcSvs01vXxf|Y1
zPckZI(!wH5O;5KC3``I?xO}wewYRTTMnB3eQBYSenKnFZm2hFzva$F%phTP`=Lk=z
zoRY=q%yxinnS3nTn*6ABkbD$yO$gk(Z)lOklDx7Gm-0%ANm2#n&1`?PBgv@h8~gf(
zSsf9ekVX%|hn%YI7~Z}xOn5k8t@zK;T1C3LyQ?2btXNpy<xb^zHsPc!s>kNh)x8XK
zuATuhq4M>M%VI*Pt3%+-SfTL=2uV1djh9HP=PAzT?jXhoiK=Zq^2L+H?g##@jKXLZ
zoG&8GazzGcc#Dey`JH8D<<pMOwx(78oPmK!_`e<QroydfXrJn{ZfCl4FB7WQ3e1{i
zLVn$5Q@Hg0;<#8vU}0zd$b3Qqxmwn%b*@trBfv!ShSggR30qAy(n1g-{jb0J=a=qC
zA9(aiQT%``aC_tF9|%FAZF?RSir`_`?|4{&bQu$4lZ!zMW_2hX6Vj5ZGJ!QKk64uQ
zCas6QCv;y?6aJh>{`=olr+2CJv%OZoSxlpf8M&C=hNC=|(jJ6az7F(MRFiIOYWkvi
zBWXN);VGW{{=Yr<U$?y*0`r@Gc2FjKcg3S!lcZAsH+qoE5@AegP4Is9`#)Zr{|vJ~
zUZf@O7fEfOlD+WIuh(+a+h=BQBh9cT1T8zZO;}{ik&qXigc7)z{?p-q@BBZ{dF+UQ
z_VLdt+bo#s?PK>}c`&SI;}BQBXidvdtalFXr^Z_(lWYmJ`Tu+XTbNx0)17eV8du6{
zNGbf&<7S5b(c#b#x3}Gjy4U?l9bkn=QUz3D0N$(r-k8AmsrP@hXT@w8JKBIkVHc;J
zxNk!OZor5-ztSx!sYCTH2L|Mb4?$E^-oYzNLhWC%^}m~BCZv@tg{J*<qfQ<uGy;Mm
zbiVPQa+LjJ%sIi$o<p<_oRXWEWKv+huilZZIzQ5m-Mv3vjLeH_R;-rJ!NVDcwc6qE
zKFna%H#O~Ee)OFbr37E4sCz_4Mqb4z{IdaoaWy(QnaQPhvXbK6<_VjJvSo}63kw^W
zVRV^aP*7%e;tFI#y`vhVXZ_6n{M4;bP*;sl`Zh%_BNeSw0ndHn_T2R0!QcaRF3n82
z3G0o_vj6sq0%Vn6+%<R5-b8kKcJ^zbP=cQEtN}XB&M$+t=S-22fXy-9LiG{<Pe%$I
z9Ng2}blOtK%bJ^;jBBh;jR?Hws~?j7I=BzzJaM?1|Kaky(DJzruP&b#)=B^4sdg=3
zTpuSlW~*JuLI{R<g@wsY>vV9WeKUWn_WY*H7#oM8dUAX<oJ{>q@d;wT>K?bR;QAnt
zqU4MYG;*n@8|Mjkb@R@g28|qWO-JmP+X%-x$cY30ct72fzX8P^u{U}`y<1ucQPDQW
zW@p_RbQeQrXZ0(d%h`1Rp@O8mT7Z|AVkcQ=-Wx5zp}eC0`3fIiI=z{_gJ_L7C39X$
z#{wh94keYo){fJxIOZS23J8Jz_qty_3t?VP3{A+9=s4Nt2((*qA#`vcqngh8@H`{V
z^0iK16FM!QAC|?|14F9G*KMK^h@&qjx27kj0k7y+zzm{`9JZThl)3cpAqSky#PHbK
zGBq|f7ABJr5sl}HTUo*PQyQV5ZfaGojCcEV>jv@zJ5uivZso$WT@l&1tgN)Omu5px
z1*oAxL8Y={ebhfIVdCOo!{QCOR6QZB-rjoYQdl4V(gKv3ud(}u`1=4hpsorHm#M8h
znK@a2Z}V$7xKpg(VQ#6Zt+rd2?3({`(O%uvSK{~~u||AQ)iZtI0<77dMNTo!l`z5T
zeLXCg2341jJ;~P`aWm6RrUUmCwwKkz1_zL_;Q>mx3qdHFVR2jP2Edy$#s#(92!|r_
zpEHLFC6tm9Y?<TGPg!|+B}M@o8$|iy2Mnicou64`?YPV)-SwBaMbqpq*)M=%(%pHH
zIaJf{VeNkY%#Xm#G5z)}v8(>{)PkbR>vIrpg2q&v1t+j94-qJrTt8+kQB@x+osFR~
zxRMfXsANw4*)7^?%GdSOCnNJy3v4+>_d@KnB|zg>qnPU(gloNb)UA`0MxvEKu5G9T
zN-Cx4(Rj%J{g$oC-LphviGaA$5cg|$5dCO)=+v2^zHxhByEIA9HT`bQRd#l98&UN3
zw(jKLR%IebU{%JWE|@ARDN!&2n1l%?CFl1!RiU9ZU1zG~vynHmhDK&U{0iJL-6Q6A
zuIyWDfs!I8Rb!xe=cZYY=D1bcVyq%~>^`jSnXb&i0{Pvg4|dv18eNq@toZlIu+_~i
zle4r7h01d_e`kN+@RuheGiMjd;sg-BQ8^7j%4|j=Libus&*+A7C>>3f4m1mjPDX%E
z1NI1Ss}mz(iZP+AU)P+IY~kjgiAIC3&kfMXKcW!E(#W+hEr~VFW2Xx-tLGQ`_%;Am
z$cHOLsBJFWhYnrD3@q;+`R*_DnHZA)c}IV{J4d3I_na=A7E`*$YApu1&3D`Eete3}
zc_M^gv5+}gpohi9SsdzLfFJ|haw!P(AHE_WKWV@IcK<p7`*Pk!K~`StbOx8srT;Vk
zg^^K@uX-Wxw;x#DAzwhPJ=IIT77Qm0IJgN>ZI67O;0;`Q>ux=QVLq`VognPwOe1;)
zl-qT99TsI3kC$s{oXgn8@X%I4Ue{-gD_Z-VYv9W=$O~MnjS65||Jxn^{d^aJsT?*j
zDG5AV7>9*L=sEF9uWU65IgI5ChL&Is;IoJ+0a^dZkNieRM-CBk(li3T?7zIZJ&Y3+
z+)vELzYl4h=vc}nzELdhE@P+CNmbJ7@29lborU{>#|d*vxAwUtw>u9?jK4(w_Mz)*
zmFZCv>CDSDmyad13dYs^jSB;_?X8RH@yb6Xf2#S{-@R6}Ev~LZnUnZGS9Tv@Ic3^R
zJN^`cn`IOn8vIS0pZjotEz|0CAfKX$WGdzQMtYgu6K|5Up2GhAzD0g27MdV-=-pD1
zjS8#g($dh54SS3o!1f_wVPWRQpzNMNI|#E{+~F~q4Df43e$u?@=rWSM=d2Oum$HDX
zJ{jtUrZ@Ehk}VBaz>ltzYRy5)*+KHx*^mnM^Up{GoN4LdkIs$e=TTDNQzp=hfXsv0
zW-?{WJ}Ou^@e~f!HeSd(8o=6!Us&lC9v<F1LVO>8?0A{nit=-Fj+PfR;^MWEj&Qs$
zn`;f)zbqx*<_v4@Kr;IGsKeKYCs66MC4+=tFRKw4B07ByO-n12vhWLj+kvRCtx{ou
z`2tpjidx7-l{1~_ZoT`oBg$kz-jr8BC-~dNkln)S?rLuG+@^&=ei5hB4>}#fzXiAd
zoUtlD@#vWw5fvR57#T`QDh4f>CTosXSPa-E(tK_|Zi4-?QJweNCCQ<J^56|ggwjFl
zRLZ^engf81XjtEUc-*!<Sa0Mo--L;I&_k1s)O?4DUu<>kb9vxNxWa(5aE&K#K$IOM
zp|J6t|IE!#(s&+7;CZ0`9z>Wbt-qPX7Kp-!wvZ&c@G*Sg9(hZ1cU95L2WIU)3ARjU
z=Vf4G?>*9X?)UA^+V2Pfp`Cs7J5qK^R{K{zgjX4d(xly?KLq!(4Ds0FLq}I%bmbKv
ze<gX#MnQxw6QNmVvEYiw<%*gy!I(!2xO@7Qy7K<!GRVZq$jeiTGYW8j<7efl?MQUz
z4U-pzwO~sq9kSO32Q4Y5T0jKy&H2;{SgcrZ*p(qXdO*|ZsMI@(Q%)bX)}r*iK>*9$
z##aT+R|qYPQ2w9Is`xFnBdN_r%@M=%{z{0S=Y=VDR8RsMY{$q_2dZ*?QV`2E*TaP<
zP#93_3{eZ=aG~n@#W2SEj-jddV^SzUgWC{0=!WiK{8G%f$T=8xncKz1`(=Uj(?2(f
zLHD!mF}KGMJJRa?lJ6G^PPjhkj7eV0aa!MPMg}HwvK-r_;*jC~F^aLKb%fzQT1i!5
zIOs~EBQ;>$t*x&kFf%J`*&`lrghuKO=e^PH8#B(=Cgjc{iX{soNbl_AG6{d^qziwH
z;vA20Du2;)29J=q%^V`3z?w!%baz;Xnnf|vSXPEYP3@MD0H02LZ{W+&$KyrfsF>Wh
z*RE+3{dq59T$Ig4-Ap1gha~r&Q>jN%(q4_#^YO89ZEvr59vaFSaW=kOi1`cU-vfq!
zod0_1j%4>*-T796#r~KI3FEz{+!gPG>E+DL*6!(zL-!5A4!YXel;P%PQfJ@@XBtxI
z#Ln%)%7cnPt83%#%1z5PS5JzXlUhrI%zm7&)k|1d1Z?yr-DUvb{oEky&7K`>G@+Nz
zYx&CP?3F@Z<vUckM0CQu#O&+~Y1kfK>5sh{7VGFSpH&nv&lf~D$Dk5f<T7!&SVoaA
zFN4jmz8oPmJJ%6dNNKQfJ_g`H$U<~X;J}xHRf9HJ-{%p8Uw-WB=)jMq$d^-<76~HY
z!fLo8Y|9ay$yXUfeYHeO0uIo<$Fyh`)voewplsyi935Xwmlo7#Bw1HbUQ|()#X&rB
zaZ+$PG%)*7{rBbi?;Dm2aVQ)!Mc5Kf(n@aE2qvf$h&Be((;0I=o$~_h$-1<v3G9gV
zk<Y#9qrCB>1}5abPY7kPr<PbU(VtJ|by|J>YhVRbW7i4_qC&}l4cR0ncXgwQ_H3RF
zX_^CHUkdsq^U1cXsHj?#1>vMi6DGDO7Ngmjk7n|XGOFb9`*^o@%_*@;ZGB*{K&qh;
z4+){zmu~@P*jLE}rnOpkES|BIag?Z1&dr&FxxY8LXc}bG4hnMf-5Ux5kC$Zyh|=^%
z5<>`AqSB^Ybev+`Yw2EFzDQ*8AYJP6v|I98$O)d>tyGbF-&0&SK3OO%oJOlROyHt4
z{eSM0QaPdUj}c-RP|%*t+ymZlsj3Bhf8yCfZ>BZD@}ap|Ay|92{9pD@b=x}--}2Cn
z-BXUqnVF1KFy3_GLLt!)(rA9Yn8QSwFqP^E&uW{z!hGJbTj?MX=47t)s>Um|arW<b
zP^`{H)yH3L_3&jvbcGqys3T@-8q<GnExz}ybQShPl!2`fM$&q2p0!8MXw@v8_qk^J
zvP*PQj~035KeJ-q`Q~p<4{;>U{G8f-bOSfP6RO(8$50+dS8csT4c?evS%C$-<YgQj
z&n4cc)n_ApZK)$NAV9)r&r5H<zk+iMjrA4LN-NO|a%V{)rS`&$C(}BdjYU)n%@Rn@
z?TT}y+NtDaC?ma6WP{!M&$6G&jM_WG?T*a#(3zbDI@=?{<4!h;q=^Rp1psIyFqw4$
zxKg277_euNmk@mQybmf3bGuzRRb~m3|B>)X^T1!_#{&r7{AqOUW@WEt<1`3PgrCTZ
znHz#zWM9+xym36d)0`7Ya!LE>^2Kggh6S`n6hot)VH6s)>#NRr^?}O&Zj#)FN9V+S
zgCeD<AY6Y2h$V8NdtZC`{$z|S{CF-&v-yjO{MfXZLa!7uzn;-<&T)beQ@ogtS4wY|
zk~tup7?1AT(IZ}!P_JSB4gGB(&1Y2$=izu(#10wQ^vp^q+!~$y*g;(M)dC{pA#5N+
zu-uYF)K$yDKZ#j_AZzkds949$3dAjolBvK6o1U6gZR&Dn!V$@TaH(wP%O;qaJYrY_
zh@oC<9?^Xl6>nWG%wUPP5@ZeYCai30MMA32xBX%gd&OmAj&OzFD}`huENXEuNmtrQ
zP{j2de*gPWfMZ}}Z0qZTo0^)Mt+C_Q9dZ2b;>vibBw0{2wba55?+I&!q!qIYEoxn*
z1r~uK89j&7Ux9x+jGmq*Wu;h0dh+Tgr}8q$k&Cey2;x#3(15ree|gRwL-eN~Ye7r*
zS~^h@^i2zfi{GZJ#?4V?p6v*UgGCbuXVk>_SXq_P(DB*=J`WNWC1r_QO>9m-^Fr||
z<30-z@=Tk~dETG=Mj$kk@KoBTnJG}I*%114fFwcx?u!-iLRxvgyg;3!D(mE6P(bm$
zEH7R2QYG#klBQ}-oQReT8U;oE+SXPYUa4*;Vm&Sn&d0IQ=4Le$OLicrrR*v6ZMdyO
zyYrNno#wfUs)@DnC1he2wYCZ#<}K#V=Cn~hD$^6+kN7hb;W7JIYP~1z<yHA87g=|y
z7evRAz{@4nCyKPdsiYXNc~by87LPli2og)`KK)e~YO)PSrBsgaudRKx$$~o^TDQjK
zzS-%i&<Q!2g%feF-s8W30nM3XPLY$*G~*yFIs^dcFXCi;o>5hNVbts`2mmN*s>FS3
z-~+IgmX(*)JYHn|q+kRf0)4!5!q2_<f@6tV)P0_y5J<RS8A@O_Q*(lfsWzK`;9S0$
zPzU!Lf!du;K!CAI1>h^--C3)+`1Lb3u4Ra(M4Q16e~C`8-%ESVTg=~#M9{~>SJbK5
z)kwuOG+~u6Nw?HZn{P45DmM#{0*J)tGreA#;I(N6vV1|)Y)6?MaTbBms)iQ=j7kHM
zKoc{VWMBwi-R?pUAzy^%Wdl_{ybLmO4b!lSXcQ@@=dK~L*Tjs4m6hBc=EVY49_4Gn
z^x~mC!y6!}prU?7-l;Iz@9n?F<S6_z+tV>HFt8sj#Ltg26;A6r@b_(bwH};ez9?(!
z$Ov*ol~GqeBMYz+K0H2rF}aiF7ZQrIem%h3siE;`acGb9Y>hXOGxC90i$pLO&%L#^
zU~i)L_a89QJJdzkES)XI>O&*I7)HZfn&?j&XahFR$R7YJGNyK-pEoA+#H;IvlWMU7
zM_pZArR;iO%97?hyw>X_C$eXDj@#v;<%5mI+dwPDes+4@b@e!>)S-_YraTDp1Y-{f
zD@3B?+B`gG1J#&i6i8C)ga=P_T3_4|nIlj&X2aZTx4IE<EA#%OZ~l5M@kMzO86!W5
z@hCZvqoQh}q`b>XcOfkwk+rb3?Y=qHT01%M1=t-1CZ^S5>>6SwruitG`{&t_4~m?;
z@0pbY=$$ujz+C{n^J_8}MOVQP7%_A1<bPZMpQn{ZuaqAqg__NGg!>lO^f!yR0Cb?3
zbS%>?lgml-kDEHDRm_Z@jin>y=)MV9QZ2@$Hhl0+{m45sdg<^Oyn=C2Yr+D3xW9##
zJZ7K3-3jLw=NASyONn}?#|<aMv?pEyEP$y`kU(H_XF<uJfa6b`ZCd*UBF?wr!1z{&
z$<NORj}Mfr<&hEgWK<BgHO8t7sV?aRVi*8-E8r>P_uTr2AATvs`*AndNeVy<2^hE%
z)!3=WeAQ9Ble7WolU9WRg<tz(k*hmv?shexl5xJ)wwHldCsUJ0Uz!WX`DZo0J_B07
z@BDexW4k9Of6}}UQN4Mn=%UCe;;#ZKd*a}Lryp7<PJ4Ubh)zW<0>X)~IENQ`dF1kY
z?=h0Q+PzOcuzkXDb#2Btm^U=~VU6Cc9VFP|n&uZ8Dj;GRF*d1Lgb4RvxEy2Z>0=iF
z$ARBPyce1_IH3QSVp~(UU%Px;TVJ2w0up|YhKuV7_A>|S)W!K&X3YSAiB!!cr-U^C
z5>z*HFVF*c$<A9%weP74sJmwjD1byqQmXat;`)T!?HY1h=6E#1;WngPop&5H3hAZc
zTF5Rg8DRTczW~#hn+;5PIg;jOd{u5?VYx^d5LQttxE8qf=|vN{1t&0RE!_oA=dWGF
zK>@C6*g4|K<svik%0R}dY&~q8@!~8(WSz$)B5IB!009}I3RwaWkZaAH<MU(f{q<Oc
z6AMku;P4LOEn_SP^{{Ic(ZHe;?yt>7Cl2XG2Wm9{qLR#Nvcw(31>FzyJ=UN6%z~nz
z?xLUS!pvUf)9FZPnVCAq_yi+iVkLg)<AsJv6<-OaNdFYCX+()UlDO8#zcBYd;6x+1
zKbe}3)A=8@23er-|H;&Nx*C}o?&DBNheMAT8XW-XsRrSV&0#Ef92|?(0WniE1%IJJ
zX4Sbg;zopoW`Ww5-o{mOprGOWYZ9&|ohN{M>+QKv7c*Paif^yltGeVInQo#fDE$i_
zn(<*1B6UBOXq{NPn1kJx4+Hr70g#ZccI8Fo$FRn>2x3L$P88>&#Flwh`+oqbFHuL|
zg+Y6nSil5U7Xj3bfpQ>q$S)`3swr`&3rEzH<#Ld*%co7PJKD4wFrC=i{KZw~^-l54
zeLd48D+SyI5|l0e2j=r;Y{iGJmJ(6vGr)Rjj<mO`AvQZkx3HJpE&q<K;YU$!Nk{(!
zw7w~sqO-yn+{671*Cj=9Ua3)Wv22W)BD3+LM|O6$k*1)-E$QKGUC-w1?Jb$bE*K^9
z>$s9kMp>2Um4+yMJnd9`)mSc%7ClZNO<LC4{1+xRGTgtvQ~!RsfRi7nr32VhC~Xnk
z2kyQE9oy90srmWyo7$XNR*%^x_WN@R;B`u~yaQN5kiQ^tNQchA%<AdNpuo2KA&u%!
z7a24z?s8~>sVi1}_=0}0(iIW|1Fqfbd->=MdnLMNj%L_8ovx&6U19EWJ9S;(Av?&!
zs|VZR0gMzVO0>WY`_5hR*@~G_B#UX0`?bRiwtGv<^V0=Z+P&joxoMNxAX0Uj8Jj6)
zhSh7@rjS5PQEL-vR?u2{xg65F-9hQ5<2Pp;>im$_Iu=d`E}XahR0+*_*rX*T-%M}J
zEWREwZVGUOX2VCv>`4dwXG;0|<9}a`|Dyq79<L`t3uam{Xd6t^y#U|DXZ%VL+=F>~
z&_mdkJm@)F#Xhjgn@CO3ea-$u2!!)l1(w;aJ7?`yYGQ47wC*;}?r=7^LT|)|oR^G@
z%*)&R8(!btR{N{qbEd+lsYEwE>4;MMG1xmz-Gd>qA;t5f*OSxpSpG(~uLoYm8|_P7
ztirx=HpNN5YDz_?<$8)1fR?3N@)ae7xPi@Fy=Un`{G0PRYr99L;WXa=c!0kqO5n?4
z>X!|cuZ_fTW4O>eAZEE&)jjHD0Ia3V=WL8lM0}^AKK(HWJE?en>sJ`a_2SiWy$cRd
zF+5bfnx67LKw>TF5!bvf55*IzgpH`{weU5#dsvP|Nh%$$W}|)mRB@l*58h4=!uufk
zJ8-6FC2vsG(ik%&HmN5t15`-=RJ63RZr-O<%gVaZcR~Ig-hcA4N`Y0u1r9X-NWHm#
zxaz08;j@11rE%nsTlsWfU<STqE(lL@K{&M-yXiQf)o68l^PaWga7CT?snY-*17p2n
zq=iRO5j6O8e!%va!gYlXNFyklAtQ!|OR?Syrb#|4E#N{nm&>BtlV6YBLqG|mw#VzC
zR%q@zp(LmRnb(tTWKSn2ggoO+jaU7F&(*W{aJOl1aG!naGBe%nA$2))pXpv&l+k^r
z;X)RMKE1x?YCo!33IgOq_Kx)j;&~WO0LuduP7Ah!++~~QcXtauTqc2551tCWSVH*t
z?%NlXt<3vHX`fyKOp!vl1lOZ-ZC$<Qe5h$>p%B679<AD$85KY|08#+^GyfDyC+j49
zmAs{h48aR07HF}osoW77X<A|IwcQ;J%W6?VQ@&Ne)R4>BEy79+jy|lUpdo0E`|&*#
zG&JH3)|*qG|8o$(D`o$B6R$WG{JN+(Pk>j04s|`<M&1PCnv)-jon?V^z{XZ~Rx>E}
z<_g?aGGWHAVN=&OxK2WoOVx3>X;EvygUXb|>Jyy9Xn@d9JF~8NG?j7`J2kbcDHiSC
zoaq^6;knp!It&SZ?b2;Z(gP0Ub`HMF7UZCJrpWFh(V9DLVo|rUA<%Lhx80w_epn0k
zwzr=4RJ<I*yt&n?Sl!K>i<xj`cm;w?81?gVoHsYfJ=Q(lR<%j8);Zj4B*4>IYO`_O
zt(tuo7MFem)KglA1B22bTS}o1Fd&Efli4z>8u#MOHC1rzlkX)i(?-n*XAxdoR+i51
z%U!hR@F|e%5!NUBlh*P8NYYUXnn=nS0#zQ0*D(&{$Xu_O37y`a`vuq4Gk2o6%p}#U
zucmdpwmO<`l3?}NX}-ZbZn_pXesuLMeo|<8AXjs`yxxc0?zm=5177nryLVX;(Kc^@
zdp`hQTy&;`Tnt9_4t1}S9|4smMh30Lj|7T{gBj9KSV*SBwJg`%U>C{rt?wNU=OYy#
zYp@V=L@kK6-Y4QbzV2UH(hOs+t;@n@ts@JI%&=fdDED;v_r~sjoZyS5@)3EmPiG#}
z$Me4c-R#8zWd*u7al1cv(8$SZ?wv8(U+tyX#HD4~OywHX2K5Mv2^E6;EZczsFZmN!
z-}{t;4hcQUp<k2ZlA_++du;s1i_;GuLM93B?sXjlTb;KynmqB&ZQ;PwI#d@pRaU;4
zy0rO@EYUibFABCem6YnT#9AucEIZn-ItHI#cXYxjY`M6&e4w?nv%A<s^YSzA_$*Td
z2{nuJnG5B}HH9TJm<G};br%^odaxqtq^nAlDv*?`O@+Gkhng6gZ+BXL%@lLqJWPP{
zPqR!qvWrBxSXtrp-oBNCIZg*r^NEWSv=iTHb@)&Ng?d=VeLfX%v>}Cr_=QaKw*{p0
zGl(XyOzQx(gv0O_WIjpAs#3~37ofqx!TFSwl++_15E@!1aXVdnM8IKqXSZleujcY-
z*jZ*8CLi4fyxAiyPgQc1FJNK6_ruF%)fK)DX+F-KGe^Jd2^a(QY31G+ll`O^$}H74
z7POM%q-a_697QJJ6?GvF0G(p1pz*Ca@Oi|K1I*;e!?s1O(-#}BJiS(~e-OHVL^;pj
z)M7kS3cNOb3I*YjcBr&m*D#4CETb_lRj*z6?pDvX9Pt2ju@e4m;1__rc?og-BzRC;
z42}7A^4FMa+ddBFyL8;fS3Fu)^y`ns)!q)UsfXoTzV}`CM%Gmu1kI9u7Hg;VtUndr
z<}-x%=@s;Uq$OYDatGU57*Wq}t0m^N*dL;BoELujdUdssy^%)-LQ*G8VJbgj48qgE
zN~0DBB$AW{_?0@Vt@hFDyiT+;fQM&#Wg!%%sEEz*s+B+&fJZa>5n&|k)2Pdf&$m|y
zm;<{QU{=Mn+Igh)@PI<W#xCYA9CMs@=ljianxCP3m{-UU)XS7_pGC*UCNkBjLBo_l
zshN?I(%n`_d$77X`bo~mwPg|?nqy2+(g)ru1}G3f@4l@|y1uH#CIFMjh_V!+)^6pY
z+hQ+{=eK`SZZrI=%xK%it|~d=`hUC@|NfZ71Mup$A3%TVAVdXTz+S^m3Ntb=rZqM~
zfk02{_0?6lAW80(6b?GR8Cz;fxR)+dV7&s`kBbY0-qAYsdnB}_k)FiEvN8Mf0Y((>
zR*$oeml6{tR~9o5C=2T|3ydgV$?3egy5QBw>Mp~z)8R5{fyR@}i8cJt$rpKlmDYwm
zI-ea~wRyLD_|#5}`~(Q{b=JD-N;H3c!#l3KM@q`i$RLi7FP<+vsFglF9UCk$!Su~x
zu?Dah!vtBjfYH$cB+I?9O4JnRGulS*y~62S&y$<4FFP>bM-87OgI<S(_`q%nH?L0Q
zz+0SZ!l^lJy^6lKJD4T}F96e1LQYdaVP0;o;*87okCzXRk2cryB3kSRl~;q!K%cJm
zsXxiH7q;0fOq;E(k3&+Lt+=@vR0}<>smaX=vAySu;-ipgJ}Tf}ppq{t$|98zBKj<Z
z6%3n4tF@o+$G$*HF4oU8`tlnzviu{uz@Zb&;Ay-3cewcP=PJrjgV@GiCm~C5ip`qT
z$8}b0i%W}=&Jd#hen#<$l#yir8VH#E@^0c_gz`uUc{zC45@x{bvFT9`$A>obP@WvG
zxqpa3QQ&tdw=H^-B+?qbz%9@;e0)SvKSaz~_Hl5{Gb`Wph>Uz}dGK&AUUZJGP!Dd{
zoHeawZ}>1d@THw$k?aMoIHA-=KJ=l-UB}!QN($a`h}G14eM19z-${JhhW!U)`o3r%
zkM@fFRTg2@FZSj{jV{iTGDg2cc;;(NR{TemIPd<_0tEDnFffZAR@{Cyoc!+GU<(~E
z{GOQp;KOrim5WMQXaNai<cEC=vHH+k_^0f<uU`dodlx{UOTu0ay;xfHZaX99Tt{<r
zLQ=GOW`5SEi3yo#W2ZgJ3o=|T4zVpbE{ijCB!d3#D}1Mm2D#?--@D(9=jstJFE9I*
z3_twZ8p;jt_#m#XMGJ_t;<~Mz6XS<iIbKl5;z~gv$l$~%eRF%2t_aT0E=Kq?gsghM
z;zokfa#gAc5y?cQK#f>a1<372^S_|u)FJ!W9FWc@tjfPf55;8vL1iPHk(@V%ZgWj8
z9cK64a{-kF-AjmzY7cU(DDg|wU391;Us&7zizTawBqxU9DcYE#No=e?^*dP&C;R=X
za2=()z2b*IouDAcKDW*(-xGpjU2kwkOw{rR@m6uY7S?_89i4g9y_{fIqfJ&?$J%)D
zzvZX~5;KICVj5DO-pr54o`XoMf^B0G+fQ^&+e@ZhLZY}dZkBeH!Q8~IUay>{*O_rK
zDS<NQkdrlL17FkYpVHC+DO|RflC>6ELTks^HMqT^;;VL$E94(_dr16(J{ofo5(sys
z(seesTeP|xaZe5}YnD#YrfkkHaOp0yg^RkP(5^u0_nZXIyO>zaww3)#R8lQZ_dPY>
z?i2=AJDp*Rjjtb2`hno|9a(8q)Mnd_W}hXXik7)vDOB`SP`i&b4MEAs$-T?IT=}4N
z@rK_E6zrroEN>z#3~ggM-w(uptsdT>4tCHz*>Tej636{u<Y=*2dQuTNk=gLx!m>S*
zn&~cJp7A;UkxoQS{Z;Hs-rc7zt>@_Y{>hkQ-!`Q^Zw%y?QA6o`f(titsvr{t$R)@f
z{1<iqv$J+T2zGmj7xTdT6W%>P_$;iUdt8y&TUp7oSN!u5KN)gaQq0Vtf($n+<_1!?
zCEk4TJcFjbVX5pT3nlnT6BX4lFaZtV;wG-+D}1rq(Q~M4%C2?QVw=Ub@BGIvt!>>)
zlowP=FpUa;88S~=M1SkDWGA0CZxYp1eA-3bJS`hFn0jdUV6Px?=uWFzA@(Uxy;c&K
zfw{L5O(ce6Y=!qez>YdN8I5Zzvib0TP_H%T-NPAZGTLJ)+Ug`w=T`6KHC$?DV9GfC
zMoMDhRh1=-lxAfIsEXFuwmvlVq&Q<(x!yDAE;<xcbx8lEn<$3+Q)SZmB`Jy&4Nx!W
zeaN=htx8QRgCm0%4aY0FZJ*`o4M>QW&x<LP%+kk1v0v+Q0JaG7yfE>!JF1dOQvP*T
zJHIP;cgHsDZ=<<aA#rvaMYm=f-k8Z<>s_K>c5d}h2up6KV)|ar3PUxyy?APNY~$NT
z1$NSds9<a6i;CZJ`lQbo!XG&RMpMgLrbdPbQ8GhwbA5+3N1VD+@>u(ayD(-m1-DAd
z1tKX46{lkBd+UbdN(V>##nRlB1QUx*v4ObGDoaI<1gI92!#`P73Nr$8a>xJ;aS?$$
zS7V^q@$u1lm7}C^+v;8(5ts4Uku|;$EX!T(0z*-TFFc+~;{5LRR*K{gy%ERK9drGP
zxBrqLs+hr)S5&NR=`3OPw0{89QlH=6O4l`(V|?UQI6uOD&oD7Nn#<Zb6@=B$fZ`su
z%JrF=vZq`}otTUa*)tNA&SKpjC;}H(IX*S@>LmoC_+Rz)r5&5U4oTb(qJYLJo`4<D
z0k9%Pf!40NqLQxomjQu+W2ei^MpUU(fU3TP=!?b!R&Sv9e>O42LeKDLZeE^%x%oRB
zT-+}XXNZ7F<<|yTb#?V0No=nQ<coMUH90n84eW+$GZY|qV^macFMdKj-0xR~Cc^`%
z2D`tYICzRZ-7Q)E8H~9v3j;vLTiT`voMgu{3l6q>ltHIk8=H4!qzo9KGIYi&M#b7y
zF~InJBjJ4kl~e`-+y&0_?=ptQ!vok)EnxQiX&nc88~pEp12|bq;E|9(D|6|gafZxk
z0{H)6ex))ZBBH%f^HuBOn*xII{|-g|6lnRGZyZ{b)F(6^iTL9?k6`!r&hG9H97K3@
zbbxCY{nxKhdwYCiHD>B0pOE<X!_aM9y-E84rIsyqQWFReWbGUdKJsz>gz7F)y}a&v
z)Ov8(t+BmYiG?f{M)H^ukD?e5VPP*W*doq|{)Z|eF;_+D?Pv3wGMY{=FYnK{kyDuY
zwbgG{W~ZJl=Sb9OF`-+i+%jg^1SEZx0#<y9Y!3Yts!o8HJ=c0v>^a#cN05aUJ(XGx
zUUnfTm1%F7woPq$RzIhIXklK(bttEm?G>b~M_&1<`7o}c;?}xrML}X+E3}By;Hj5Q
z2|y(N&~^6^T#s6&W#XwN6PVjs>2MVh+#wh+{Ri{3X8gBc45(D||4%T+hjdYu4X~^Q
zRrPgBpxI)UA{XbzqB!wB0QOY?mpNMCr;bM6Sa$)EuHoWYZa_-C&^z5i3pD3jE`0Eg
z=H)x!VT!7+Dj&5j`7)v4RLEdBmQ)Xa3d_r5Acs{1eu(}DaF!Yf=SMt)AyoR?q#*f0
zWno$~ka(6r8PKs886S>STq@bVN_oD_urOD)osI&S&Sb1=Zwo><R7H97yV|b_7(&@^
z6fvQG8D<_7N;I!gQ8&QUmH$1C`k&`K5@f5!rZ0zv&SYwI8EhhCCi})vXof>n<F7OT
zfbM2L;UtP!v3c*uf7D^0TV&l=hVCm~Rx9U7bYJ8#|8wpC-{?_2+RMn{UluSkQ_Qyc
zP3zXC`DQ*11y+Dp{J(&(|1IQ#R`^QAeZH9iNZ<Y+V{aW*<@S9KOLup7H%LpjfOIzq
zNOw0#mmnn_(%oIsASK=1-3`CTo8J4m-|@cxIF1a)VW0Etz4lsj%{iBfrR9^9YQF#0
z`(IDWzh1W{`%3+6VYsNoG%jhUHNC$N-4Nf~{)KO42dTFgGvN&e_Bbik$z!1Uzsvml
zCz&az%zN<1C6ma#vmdsPaZM}Q_@>xvsj2CEtvKbzZF*1i(#nsGvPn;?B}~4Jj`n3{
zaQ<sS|M>4%8uaNaZZx@^+*}AE?|TYQuU3}3AeOg3mX;81RvhrWZw@yaTzZG8>1liS
zol;~YzA^qY+WZ6QM%{G>r6dbzUT!I?)&IK){0LCJOHfQtZ&|wH4c4ASfQCJ8N}Xk&
z7n`-gU`Uylc52$+k<pTr*>P9CyQfE^bRnK*s)Qrq&t}{2EvHw$F`Y-20VmToJ<~+a
zYwa1H=$&4m3o)QAZx-$D?D=q0lIP<Mp#DB&|K3-xU>w;&cmg8d_z^U-ReJVlE;{Tu
z0*ubA+efjucs<3~J_k8s&KLCk13X)LDxw2UE0GV9L=9YQ{qxXoIe;+#>l>;|X128v
z+O%*J)z;QxnrmY`Y)*)AdB3?a4+yM%d_=ol?UJL9%fp7jMy)V?nQb!Vv|0`Wa2y=m
zZ@j;Mk>N0o4Nwll$tRPW6M3>KYQwEyd9uv|hB-}|wma!E#^11pRQF|2f=?E?<+3s>
zpn-|W<F!zbw`-MiHwVWWe<wtLJP8ZvehmtMP4xLQnri7iqTI{98fGzI@JZA9^ia+0
zdP<y2wZYBBm4q)+tfr$A>E&@_bX^jxADRwyY3D4U0kL0AQ{C~LKU?6350>&Jjiw&M
z2^+#dEa3Sh7|b0|3^c;lPxORLwuRn2o`Uh9g^#55^%40*v9FZ%Sd@<h*4NjUl{c$;
zKMhIDvs;~avj8?{*o-<wz?I7D>DBb&KCc7M`}c<a4a99q?Wi>3{xcV$)8eqXBm7IN
z==pG0f`^C4a`7C@;x(^4IXSrsBrbrMlKT%Wq=~)GPy$0=ofU6PLV8$GuefL1E?kN3
z69fPAF5i|m2jCs9E7t+2h(^=X9)1)LW&moGg0@5Tic^9=+SIMjZpgnqS9OsNvt@vg
zJ+D-;Egx}ru_8X+Xeg8Z2Boa5OcIYr6d?s@w%OUSaCzOspW9!sST81B=UGe~15MXF
z+4ij88`1z~!1^#;-<IC$WNK>a>f!cncz9|#tKe5A=2#E-TWM*)v-BAU<><@I;-X=V
z^!(qQV{r@qa4jCnttKiEH8m{o+XthirbsTAGHeP8iX@&ZadHX-|NMN3W^qnVPBQuu
zfhdB}pA+w=+8cpt%y6<F1sWdygPI%<U~#Ve`aCS&!gjrz=Jw&vVE(cY7@nBTHcQU!
zJP+tP=c-9Mz2r4jql|~z!~q-%l8VA`z55Ix$Zv@J+**FRA|0vallUQkS#T7$;5+^b
z04>COt~!;?iD^egp!XsrtNOP>0thg;plxk!Njy%lKx*?T2^&d3Ko0=N5Wyk7JjV+A
zEB8hd!2wxvF4aAd+z?b&j+=~!fm!|d3PVlDBql6OzmB%9{IL=kq^Y3;`^mTTp)Z{;
zB{nvKgeCw5AOEB8D?OQXPcZRF+|FR3->!Up3O__{K}I$<I6J#a9tm63X%NrLanpSY
zCz^F+Oq>|w|2ZY74R7`TM}W6)o*z2jDH2@yVLZ|GD!x%tPP*$6!Y1Vt$6;*OzI8f3
zLVL;u{j%4M*XC9lGx{n4OcJsF!B5WgTl2w0U2g<AzB?|$v?u88)<>TGea4iEPddLx
z+g@l#$>fmI6`SDtdMu#1j|f$h3898W2aRwPUXw)wjesC#ZA}P796+WVf%A36gz>Tw
zXbJBw^#9r+6&$4;o0t%_T&aZ1@TpVZ3XLz|m6jF}0b5RfQKKNl!7(UIj@7F907Fio
zZEhZ>;tr7f{~-3Oj+ZCUE*Mz=t<X_oJ}>I~>!a}QZa+zaSWp1etPb%91p|bOMT!>`
z<lRR4!v1q1hDVt!;|c(riTiXPNXpNTNi!hz$+IK@-6LJf^n^$wy42x1?upEz=IUff
zmA~#7kZzTH&53(rD3mueGD0RqiAqYMmaZ#~-LvFprMZdT>ocMwn#ie21TV7z-S*7g
zR$VbLBL#H03Z4{CU1M2=Nmu;=kW6NuNm-wSMZVAVc>n970jL(n1l{}W777{~##uq)
zCBJuv!&@I%OMjrP{m~v)JxJqM^8JaFPYx)l?#=)9kqZfHf_o5fVoMYS)Ip`%UP($%
zJbFl{Ho?Fg5pm79zxg7!9nWfQ8Klzaf8<8_Gwt-M8<|tOjxHJhnKIqYHvK#)_FUNk
z0buXp=c=dUMz+c7>|T<*h3n2)_-H+TRz^QX0%k1U=McWhO^^=vMSAD2Mq6G`N^ZBM
zb&5i!!!*D2yxc>hGFVETIdZ0z@Bbz4gO%tj9`8?xkj44OCq@PZY>Gm{s~7$9a;NWo
zIse%;E-jE%lNJac@{_5pbpqzX*SHhf?YjNc5g-($0e6ya>D2JB?85sqmDFi|{$<P|
z3ka*)+WfQevU)0QD=$i&N*~L#>ii=jAceKunn1fQY>P}A4t|ix@Lp)*^PG?B#YEjD
z0RMjXc37c*aBx2fY_q$O_eg?sJ=%ueck|3l=j%~g`;*9k`aZNZALPkDl0|@sg8C`r
zYGEBZAx3ocN6o8ywxQ8lpoct!UB~5rRQYoqJBv#PK(-8Ai5~OMmA`GGC9mkZy7KBf
z+m{+|(4d>^Qx^PC7vKO*BUjLq#6ghppLLG{4?i^H`4A=^PraDb%|BQ6UNkQs{Vu4e
z<`8vrUbnEI#J{Di&mPDyt`H(snT`Oed@8p`r=T2Z12AQ=Oc(G1e!Y7Tf%oO5BgPXQ
zBhj(fQHM2Hlq8LoT3pqckha(y-m;*mtfz8u0@7;fN_^Vx_Et)}to~39X32@5Cj9S2
z<<~o`i40^&E{WNwwZ5M7XK;Kxi?$I$i~}N=3a%nia<czUhEMNz=%sv*UozKUbq$04
zN~W-9BP#-dkMwT`f#LI~t6udkbD*@e#g(@QkxBf<=%n`$^_3f4Ow+_9l<-CpNdl`z
z3&&kt$u78&k+SBg&sjpZXORgzhCH9rqR+!<MK3c7s&n$LS;Ls()-3H{06Ji{&j%u%
zmD)1PTW^7LxwOFc49?^ft+8^OvD)-1>E4&em4orIF=$|P2sqSTSKq__sAvyNoAHhi
zd_?#m>cS;eyjQK~@J$kr9TzY>__A5KwXzUK;E?BI$1A-{I7G{dQOJMn;J^9;#2^bW
zj!A6l7Q%XDcfOIeW?Ri0Q*(1L(Zk81erGIPI<}Z_%XhCr!Hif;9C?zHlPgYbh)9jc
z1Q%Uy7zQ8VC~|e0BK}fHsFMo!fN=g)NZ<|quR_BA!sO}_qBlZPHR5ss^5aclOPhA3
zMth^uJ}LvR=Lgat#A#3NahlK0=j5m`+Dcl%57rsr0%VBO1tIc_7zNzeUq8!Qu<1BR
z!@V7%Q&3xZwZhTr8(z(3viOD&#G7B-eNOb3GV@Ow)Xy-lkMxsey<jBcGM)yAHAmuZ
zXQ@TSFT2`GL<Vs@PfuAe{O(qt>Wk52ntA$Ub#z+aA~74pofWJsY4pXDO)o8})aPB(
z_MN}$0&qesA>7~e6fu`zs8?Dpjk;oKZ|@_967g&|x&hO7hCLEho7vp=6!)s60t^hz
zY|-nh<7k6s3?tuD@*@--Eawvn6$ux4oFc5LLw(<cz(}~iZ7Ca8Hy-ZQp{8XN6EPyY
zeoxT#9KbCZG9@a3r9<7*H0+_E<)TqqFP90}1P~S?lEzh%i*?R3c-WRTps%-}ryMt4
zK{`oheI31Z-mvahL1d7T4eL2ozKC+h;k*$g@t*aPj6B)g3>oi&G_w8n%IP+&g#AQ0
zrU(k^zL466Qw=LFPGwbK#Y)8Sy};%+RtHdHps@xKSNVi!UYib0?<>+idTgmqahM&-
zhk&UMQc1UqNISr7!bL%uEEddf3Y<TxS|N*56v=HnIyotfmMRZ75+E%*<?Mf+B($hM
z?CH9Bmdt0`KztYSEe0SP_n)j13oLSbwYWzCk`J2Ws@~ZG=EYB0+)M6rgA4@)lcEzo
z7fT#mJX}Ss+-};*xGq!oX`kW<6}>%`ApJqhn!=HY1OjycGA%#>T{_Fb6BkTRK{ps{
zw*f}_j`?GLrJy2axVv|HE*85G`2C*$_rLmJeuzUjmR*Z{!nsX(m=J+Ik|E)$*O(dY
z(0Y0{^pEY)r`>E9KyUX3<y_8Dhksf}Ln5wgL><<5B5+5gdw2Iz2(uEiFO5qe@zM12
zAj`s}BfDM|*SiBeTxPdJc}dN%XRiR{)t$%^kw){wS3X2CX|IKArP_1FNE2^}2F1=h
zsAW=Kqq6QKq(Q|salH;7Nz87_d$%N=41>c<`Qve5(MW=PqmMH(C?J5#azoi`S3eT0
zv9S^d%&1ERd_NK`DC<&@q8q1}p?Ky**^D75mvVh%Zvz>7HDEizWUJuGeHiJJGUWQ<
zI~?=?FDQrk&E2V}93MVC#V7=UL$whnJI5%ZFQD9&YJ*uuR51?O$OEAY{n-52SVOdq
z*OJQhUwydLv_UIXQk&M%rxNx)OBgJMymxxYks_Pqxtg$*X*K|d?2(`iE>)E%lemD5
zBXe~%CsjnvQGtyPqiYP>0(W$qj%`;9<C@gkIgMumeSft65u>k!<0)u2LPoB8NgzE$
zVNZ%H-34;JKc3ZCo5$NRU|SlrQX_q|zeaS5>SX{s;p4!@#FX|`q}qkb5ZjBvjL=8$
zhmD^iARW4yqp`iI>8XwGFQmYgQIfjpQ5Cg+ul~R3<nN)b;caFYS%4|u`Rdd-NKG5(
z?%_7)`t1Gb1XKKl%Q-^w?qpGsd0e6zF$WLq%}4{zN{ME4G{0Vun(m`)ez`b)V4njV
z@jGcF<DE9kO9Vvb<dmtTmd)gUiB#f5<nU`10ilEP*PS3DRur~Ofv_+pVf+!r&7G&%
z4V51%lbq__1-h!v{My>7YunplRnqa$zbjN|f{VEVdhXm-B?(!B5PCbw?oO}I<?no^
zzEVDuaXZwyIXro>yE)db8$8_$+LK5tmwf$(oHE2{W{KIC&t<Lj+0b!3ms56(i@67f
zA!Z!LAXYdB7PYasc2t|+B(x}@zyctO1>m|jhF`oxr^OS`r=mf-YBaY>xWtPwASoy+
z?26(Gt{tXzS5-`ujM>#SDAW_a2VYeb)7p6)m=GIeDUHnJGw%X%$m#?c6Tf<ki%cT|
z*;4?0G7;FbPdna8k(;QTv1xUE>8N%E)B*7e>Py;p(VkfVVK{5$>;5`*A}ONloGCEF
zceaL4x^!q%?XwFPKc!4A2h0Ih#N&k6K28w$T|G`X!oQE|?~!~g1qRzaipRJ6vGkzw
z^x+DUjE~P6_SxeRJ)kb#w)zkGI#z~<u#0PIetxfp(@DhM>Dl$SQck(f6u4)<A63%O
z@VkpGC4cH<zJ_W}o6-u@V?pf@O!V$?rj$yT>C3jQ(qg1Fd5s#7_gEkjey)L@Uq9T0
z2KZC2*)6gqYLBLMDSBRM`l98BITo!?mXzCktPVz7&wki&)ddmHrC5_$bBh=YC!eBG
z*Wh-z1|^UD$YoCf(Y-Zvg`A&@Ub^v`Rc2#xl1TG_nXz3N!c7Y1^1?5r_zoREUS$fo
zFV`OY00}lT@3@MQAlMNC3SzZ;&jC^~izK;g(z9hz<+4sFAAu7~nu%toN>#<~Lj!JP
zu@$FNBr9qbgPtHhmpv%qaoPS5n3MtuqO-?aW2aJk`*1S#w<~n?v_%%^N@j3JIcpnx
zYkBX<y<q?42Jshu;!E=Lx(uJFr{eKOsC>0jx)N3@aQLlS?ghS64PTZN4LLKEV^Und
zsi}c_DkvyuT10!oBUF>$mYhiH49qb~<_X5-a5$*FoKyII7L$Oc2~8ZK^GCdv?Q=F|
zbTL=@5zS8>O_7ohybC85&`vRGvdh03`|656%$;L@6t<u-4QOiX9zKN?#0Lz1?Z-XX
zXDn{wNWNVRRMgoAJM!e$O=bcmj}H*l)>0zBZ^+#BSHK8mo|Y>mLHQ9IuGu~-q3c5~
ztD^`sajfS_X-LU=w8FxxKR3NKho0M^Fjm{DIk&&Ej1SgSj0ho9M?An|d99G^;Oa9@
zyLC7-^VwbLVhWwS^g(kaJU~s+_%&yJ!JFaO3H7kV=H4?pC!=@Q(;KIM_I!TLHG$Xe
zydWacN;dg+#!tM?riOQ6wGBHXdjP~7unEIRH}g2jXI!yeQNeytmt9wfc))2BoKcQ+
zA9T5=>^{exuk5|FRtRIYU0PD4(C93Yizi1kF243w<ej%4kELujErrDCaf#93xMk@^
zb?aHz0~B3z_ZKxE3Rrf^qIRAL*=<ZyLlq|mR-~Q1pwp`}<?&{Fd5!i@9UNxJj{d63
z0Buzn7EG!-#%G^?@G>=fJt^K1+debxYanud^W;_s`@m=VcbcIIm^-DjDK1s=TUZ>N
zUcxdT-E|jk-WS&nu?_ONsTPV|A_a-IzjcQXo#k`N!xjQb4tV$;X<^}`EGpo{m9}Y_
zklHif@|{&z-?!YpjF87!cuRyo*+}D^rBnb3%5-fa6I~ncwQ+r@p|g{nY9V3NR%#uW
zp=(Dx^^wj)waT&401Ly#?Sqb%cwJR4;oq3vB_?QwXA^W^w8aQ=rOEK03LXW8D*NqT
zJev^-E349}rn-?Ye_B6WgbLfN8lhp+{*DX+8gRsD_~Rc_j$@m=Hy;qu9su#qQpg|T
z9l#E)1MFrwYBbR^@?_ddC?oUL_m+n~p2m@)Lq1#l@tCL8{i0Br=?s^?HnLM&moDE^
z`6rWVr_i$RZ{ms(A<+z6IMw3W)aS3rlvG+(;!fMutW=_8j>unbEdzh}?4}paQ^LOs
z5jGfyzzC%ixXWO7zzxbr6qPcA;IJN2W<o)PJyjXc)$IA|r!WY@OHQM@@P5WgbYHM!
zt^tpTUbi$gJ(koZodxetE`SiC%*4-Y*|4XHK)uqr*&MYmN0eMz6Na1K>L`Iv{qahC
ziVAToh0@#}*5WEsCx=WVCKWp%K;mLb`aQWn2S<^>4<%GvKsvl)wVb0&G4J_f_O;54
z!L-k-UP|U4b#xa6?&<T4Zj_3IO&+wUMr4y~*0Fe+(^QQ~X;;}XP`%=U=lDa?h_J79
z=W*i`Qhi%BBvfA4i((8Bvd+GF1;`8aSN!ntN15aipSAL%6vlUkW<1MNwo`2C3-7zf
zMTmpRD0{_<3XDSEBs_7sStf^}PSezs)v%Y=g8!ptwInAtRh1lU_zffl4v#rZHuH@I
zL#b}(7va~h&G~(_vZ+|@>nguDnoqg7-p{mG&Dv}2Ozx|wsTr*-KPB-UkYG?7T1Oft
zsouD68=Zk=692ZT1nbEFgP#{utNh7H9j8yVWcIQtd`k;FJXch4Ee-3b7{Q;t`L(>h
zSg0gQj!R?2L!X{3zUizY9H62@8~_wWCA{Ra&F{EZ4<~XhSiIk}qFPB7691+r;)ZT5
z!@tfYc+k|vOG%bjP(WZ}LULkGdDhl)#+O&9S$}ifPkQG^ao*61<QO~J(AL)Zp-eCI
zFun#N?=o_ZmdE}!wIZJS{S)c<ECPb8xy;kGg~m)CpjBgYU46BcG(AFvvL5v=>eB~Z
zi?9d{6&<6q&cK8yhQ{FHBJ(K_|06y&>Ar0IKaS2WTL18{7?5vxe-^t667Q;!zzvSy
z9J2Yt`=I(m>h;H_`)XGY=gL+Wv`<~0rpqtPfbV)3Fq&Tf+ebStM`}DWarmwXUK=);
zoj|Oe&V>c7r}=mMqm2y>nN``S4m%?(g)W!7b}f&CM7A&Ao6n{n>(9QyjT)Y<QzTtH
zR)<7$KGj<sq)I2ycm06{TP-*jIF<d01jkvAt}cJeZ@sGiz1^@nkIKA5$Ij^ibi7ix
z0X<SVU*|ND?ZW3~)uZ{v+@nZ6B`v7X?6{EO5og2!PePy{{l!^!p(iFOjyW@uOq~)V
z-&I(K>)SoV!ux=dq2b{kbEr(&&wDgd_YhJmtA}3))aZ0#+YFWxT4}w$Rgi$Gpckfx
zEvek0c22e_#FQTQ8h6K7yjw}~OZGBqcvqS#Dh>BALX8p6erw-jBI&)p^hH8JMJZUy
z=m&gy^P`T`WJRr5b?|qhBGaRWSO-ngWm!Hpi@vXK{&)n?em{OFf<u}klGO%<c!HRh
z6fpVx)FQptdz(}COmA&zWl07C69xl!5N*`wP~r7poyzY8iGxGNV!jCt4w=laMn>L%
z^mb^l(sFJF@OA83{VFPx%0;-gW<c3FSWW`=_*7}VB%aEv77-hZDwF0;78?sG<k8{c
z0R|X0Wn^T8iR)I{BfLxHg76U#kV)ak7#~-lOzUh7l=Enr13VCc6wB5MCg~zRIi(da
z{h$<i?!Ge|7LwbhtjW{cHeq=uNXottK8>DVR34pZ*F!j6q%)Lx3lb8}@dQ#C%uqTs
z94|75x<NWgVt>YhvOg4feXX2`Ck^)N?bw6>0)XxjL;{#|5>ccqEQIILgMjY~BG6W^
z=E(cEp&T(c_drQ{1m7Qia>IK&JK?}@8;qBWSfwf9PXfZGj$k4m|36$}K74TKy~gC<
z=BoJJ1|stT=*HPO*>TKy$*N7oJLpXW+S!J~+}^nx7>d&pbYh}aYs+VQQ|MhxhIXkO
z8}j%wm`X_fjgjmgf&Z82h+IWQ#dU9M=5+FN^v3vHwEpr?c~04Jl~_}FyLwpiJTATV
zDW$!`#o2I}3g+G%TRy(3%fHo34!}AwJ2R303_|*>vL7GuwMZQ)iYr1VzY#Q1e;FO_
z8OXMAYi5-d4Q5OZ__ed;_)qPTX|X7U=Ko*q5$cke8PFO(XOW%5<QMYu15k7zF2JLr
zuCp+cfCvd~E0qG0B3cb8I+VW^MI5JZ%MZsdFSB+R>X}f{ph%r0VHX)B7XV%J|De#c
zE0x><9&ki!`a{nsd>+qvybn)+ubR_4z#L`9@NbZrAcpdr<!<?Arjvt{KRNYrMB?|U
zx!_Knm4%PR0Ke-mbgCi!S7dpL^+mwr21Hfmt`FpKXjuzgn@g~VuVPU>dAn%xJi{#N
zwL{+aNW6#Xm-y-|Gvmgd)_N{f2}b3hkVCJzQ=jD<=W^}dK)8a;m5Vp^9wW`8!A8-e
z(K9PjlJXrx2d^0Q8jF+!#&2iO(0~~oNh437phRoHtQVl2JX2_+F#VS3Xfp5&rQPwv
zWPu;PI`~_Q$+2hD`Vu;1rew5~sBY|1O^#8`+^fauY4NA3hWo1nVQs8S>ciCaEyp6a
zZcT)$mKD*3#qzLdX6o-3WcL_bqn8)YFVX5Y20LG)>jY>5eY|U;2Q^{ki3LDfzwgv;
zakj^!XY<pO;$m)_oQvtg6JvpX(xDavftB|KMbCT%v3hU-r#9mcRjvGfPVbcRS(Aak
z&}{D%E=*L1(^O?b*o!V!5pGhhrGl1)1qKsy8^S!JHU_#s>B|?)5A{aV-ZV5c=en{o
zGF6yZyV~HTr6u%mlN=T~-^$|oH832~v3jU>KG3^Ofrp(xqF;|*hTp!({aos`0E*bz
zI6tce&FML8NMw^3x2LCPO}k(jbwD)}#4qckK0So!mUe+dgT|zzvlKX!JAv~+r$p9{
ztNkJIAXh}qKQCc&R7@-%x0C<+=_SA7Wi$tPbBI6QToA+x^e!)SZ2Hc)46QvY3>e*V
z%Q(>2S|ES>5rRLFBAwrXFh*f~)UgZ->Ctv$yA<EyW1z(5ojr`ti{N6L1CvC?59Lo^
zlA~%?v58CH3)tii#98FN`o{wQ_%6rLsc-QpUq7@?s!2p;^jt4N8565N<`vmJ@$Amj
zLjeP%DvWM~@ZY%e^gWHHu^?VMLyT(08~F-jy7Dyyt=@ikeM)~TEf6~~!Mt&a7;&}x
ziYnZ{y}@Yzl3Ts$1L9!{2jiwWFthA-7v>Ex<;UruVW`*VsTIt}axTc%m)Pyep!^v7
zrbjZ;4+uK2F+SEKC55<K6#JxPXfVOnB>M|Fl1=MKi5E)x%3^o1k+Z|g&`;}3joMz)
zM(S-7$Wh_$f}{PJqD!DyB7bd;U!Q|~69hK=$kvYOhY!9az~D~VdUI&kOY9-F=Z~7~
z#W`Zty}Pq*2%7aDijHf$4xo<(E<H&6^eaQ2owSG<_;gy+{Zqf1nh+B+qQVqPy@Dl#
zXY8NtnWH2pM-NZ*4nAqq`Itu-iHwUGg~$0k%+mAnJOgHC)`YW(y@`WGj^7aaNuj-K
z|A~?nJL0>{RYYDSUC#O58M8f2fbxp`oBcXelhP&qsn)C}1i4>V{r5(vmRAOW3~)fX
zw7hC+nk;q4P%hhypyTI!&#c~}FXGuvqA0m|d&9A8y&}H!?3NaCi450zGq7jQ%Vm@*
z0d+MQ-g+Yfcta5pL^Z^Ty2h3Ij}sncmFEW!P}P%)qR=gj@HcC<(SHs73@6UvskEfG
z5PH)yq<(+p!upEOv0t!d>KS29n|xBQ`daO9xf)AqfM$1YgCGK%L%q%J<~DTV)^5uE
zjVrb<EJo^B^#kwjLVluWxGfNuRZFx3(wbZ3vs&0vQwKYLDBcOjRPVGH*qBC|lza4Z
zr=|@Gc`64>BC!}vgSyQ<Iw8S79ipjVIG@Z#>v34B>V<z+=nBrXT2QUBjGpm+d^|8|
z+_;UbV_<RnfmKmoJ@r8^6^pW5MJV2aEru}NH%V{A4Bkq6NXpCV@ECq$ek;avK#vUj
zjl(qPVzUd;P~xyeqrLIek(=;;?h`>je^_Sh)M#aYQj}<a;nR0J&fJ>IElx-S12i9=
z@2jO#J{kRZfu+@$GccTpy4^_N6h@2d)KOUo>2__rxCy`|Waeb;E$19v*Hwl#pXW7r
zzu_DrrKo>=$A>LnPoZ5xpl@ZEx1W4+lSS6Y;&jfXebpG%c#)Xx)m+C~&<xDO!smC#
zXET+F0omrhNXYhX<@s<h_qNT<eX@U4zSUjj_MX23Ya>6)Tm`Gfd=7pYtGr+EG{OuG
z1&b)!?V?>gzkXrJ$<_6>@a8vlnJ+wWCyoa{x2C~|+shayXU5=i6Pa%b3=1fiT<S(g
z>FEqxkJ)28^9UhVaSR943#q&(ks1yO`tyk!tJ|6c#nX=;^#J#>+3_xRK%P?hyt7ha
zuyHaMKHi`JhVyk;AttwDObBQ7orG}0kNo^S13O8sTc%jXTatkVq^Rl@H%*w1Q32!|
zPa;x^T74UgnceSje}?XV?ekZzxEf><h<@L{%RIK6F{x{5tq<2R*iRDix*?WL6?M$N
z#n~MiU&X;p!o?j}EsHGVMn9wBHla1OjwED{6WV8RVO%%=kZGwm{sZ$mZ@bFN*uq1(
zS_M+l0sfPOQ29-Bj@d+SfyNMm#k5sNj)YKwav^EmV=X~CFr=ME>TCL|{TYY8WiKdW
zW?*xb8Y2V#(F?4ujLuLGcToNMr#<0n?^B#@+y}iquJPqZwF?a)9#5B0Lx>M|jPm+*
zdNz8aL=RMljq%RJXNpv`^=)i|Z^4I&i)-UCx~W)MVOL%%AUApuC64CVjoX2;qI0;G
zwmYRH<KxFn>!tbG8aFs`L?TeKoR$~KmW5KZ`A5!r_n22QFAFs3wK6jom(&pJH`>AL
zvjj=)3TTk=hp&TnCmy`qnCdu21(<4kg<XaIb34nML!3u>#?NcfwguYEwISUcKN!q+
z$DD83X-Gtc%XJ(zBQY1~m6!BTY%lg`-r2KO62p<9b?1>|4$W)p6c5^oW~$(yoxy~J
zhX)JCd<2|QLnaZ|D=I2{(@I%w8;ugN5_~Se7A>Ykd&0J23gr7UD?U&;ABE|(6y=!6
za&o8dYl5fuP|?%lTTDNNnXzrJ?`G++K7A~b)m_=!+q<=&#|QRm=ZpK5JSQ4c0h&`$
zZ5V9KF)0fTin#dTgCggMy`i}|EM7_~cS2-DWK|9AVxe86J@w0j{(H*2b%h%ul-fgP
z{GIlE!jdj62<eTi;|{d{V~4#*(`V+w3)w$kjZxxq>cvCr^@QzXl>;j-y06}08ghh2
z*l#WldplX5E{U7kmsKP+)Zd>Yw%p?`f8{+d4({DEUIdJHzF#$ar4$$1GDwR2#$b`!
z@#vg`m6dgTZxW|KH&eAbh|WJiWHJB(lHb47YGkoBD$4kDz?UD8$}xe05)QmZ+kfYl
z`dDGkmz|w`dR67d8Xs8n1zWm>+!i=;Dq;}#&sGx|>Ms|0_*QuACE@JFZNmz>NuYde
zWJ&dQVvp%~xJxICt--TNTn)`LA9HhmXyt$~{p%?GksDEeiuU#9zbb!!br-HyX*5dW
zIo66MBP)Z9iW^n1i;WPzk<Ylw9xcx83~%w8HVexns2ACcG75ZATv3yjHN4@Smlq!}
zYmQL&0rA_-GZ=TWYvV%hkeV@aoeU0CcW>{IG72#0N$CCL1b!bW(`n(v&e_-~(TvSw
zxWf)pp_;?l4}sHp4`dh^*hVeahj&b0XutL3RyE1$QuRe=^ae%x7#^qYF|)oFHaAa(
z7Y)BAwd$$dFeO%04$*f~c6^OU#2qsuzkg1Wf!Hyp1ZD5({rGI*gl9!n7@hs;p6e}#
z6kM2p1E$1dRI%h4f{=+lZY<+HiSvb+x^qz}%j7<LyZ&tf%qbG|B=ru&f2BM?`Up$g
zk=EHLsng)7lJML(C9QLyTnBF=bEmB<a0(|XV~IasW0_s%vrMJ*&MH7pronxF*<-rn
z+bsG4&t-u9McFpu@*%H#vx<eU)lJ#zWKOefy-RNd=F+5*8Q(zL#%=onOHQ!Cb!yM<
z(vFhT%>Y_oM~;*TJOL}RbYf}8xs6X;qx->>6V&s;OpAt+a!~_XEB~YDwbIrV1{P_5
z%X%}>+0>y})w@eH?f|hyE|X#1k9;0TgAQjIPf$_9HFsu9Z&PnnA>#%19~}AE^5s4?
ze{Oa>CU(FKUoF~4?mWCcigOEBF`jD&1T0(Dr-xe*t=Bh6<<_{D&*pB&_wQlQsZQ1g
z<hP=Xe&$imWk@M&R#R3zQkIsfEp>Gxype(8P`ZC^r(cqhpD&41e0B3&r8Q~zzL91d
z7+6Cpp&2>(R>Un2N>^J33X_0s8RO%>*6pRVzZ4e}6FEd3If6!t_N|R%kBEGIaS~R8
zN;(ygm1R(N=k9=4oM~)WZ|myHWoc=pZ*8JFW<B~<Cx{fn3<VaOR|_mC8Sfe+H1yOn
zrx;$9DT#CA%lA<sn%@^xUIh%vW&)V`PLz_e6Ecky|11L1`o7N##l$6F#qRtp82&ga
z<qf`#g(izKYKTNcM7E|CW#*RUDjkc9`0Jman3<XT*^ueyw=u{un|%rJ?YAvQ_`MCv
zA|v3}4iA-+%6gV1Ru-{)w|g6-@K6Z--r3amW%_wJl$w(K`S!p3rJpZhNjvmyh2my|
zK$+w-6?4Oqo~Gik8bII4{%6cSWraqUX6E9$g?XN>LU1`*mWafi8qZaNnk>kA%y)J<
zxgW#|FWl!poXY7w?DfR)_HBXsKSCbx=pazWWZr3hBAlB)Je!XOM%{K6YIDOAURFM)
zGn-M0Hr|Ffz`?;imaDmh9Cl}yQt$lpB0<+#U39ad*KU9x7#QF|NJvf&>yb{_`2NL#
z=L#*7(`MN}63=I*QBQu%=zDtWD-geE$9=7z)eY}e@v2gsX#&5e_wC~cA4uJga?f;z
z!0j)XA{gV}Nm}smkg;&O5Cj-v8OXghTa@=^(s&K0=W~(s7;-@p@Q_n#O6SR9!lmrg
zCzm>1$2hI<d&T$11B5_6J!^~t<a8vAjBT$<GdTV(Vee}yd`<hJGCJ1C`e0}8&Dc=D
z`Ry;k0b`pCOw831YKz=x=T)^%325}|FS$q=MEnBt8Gcx6pI^de{Xx;kC^HjjbltT3
zH<pgQD)xho8}q!7_ei?4-eSc#!Jc7_%mL}q&b6#YxD!88ct}uSBaV!01c~nJ-hkgK
z(m&SM1bcgb|7}X;%eqWrTcH^a?r@J@aSs(c1A(_tOu@l+i9-27ASq3)pbl_*d`e0J
zhYL?-Ivcimh4P-AjV-XP&Duj$QBiTTH90A1lT$3p9i^tOs_MH!x}K213{Zzxm50e0
zWN6%<-l2ecde;a*F@2MG2ve8#OH}JvoGg&!+yRF2kZ!@()l~JfBh#zq!h%AHN(_pr
z*43&psU8v|dZT8yZNvOy!^(4kp!74y5UYPzo%QbR?G4nTmoE^s{jKg7C{pXmuNbBG
zx_yKO`T30nV6EkNiIo7=WDU%29R%@$<jpZ(ziRA-{Zyk8az+WD+WyF3v9jaD=naOC
zg8_Dywm{<S)xCc!cV>^5&o%gijjdwmnY}xo9K)<(Hjeyf85!}0BisW@pu4VFZIenA
zMeA#$a$11DKiriZn#vR0J%e*jcw-eIkT*cXMf=`*$MjvWj@=QmvBjW#E^w%S<awW$
zM@ClmVbt8)p(6d)r}5W$B+eI%afajsW)!x+RH|&ls3LgXuX(x67nwWVJv~fGpL_hk
zBhWW8ryP|_eG^%h#@l}pdz(SlH){BB9Kec9?~S(D;7xFOumBbW32EQxaZS(}gSPW2
zH5Jr@7w@s$RBf_Y=^}9H?OS&qjwPPx<m-2~Y#a=iJpSuBrwi>n<IA}mGVu2NxI$;+
z4R{!!85M$Y)fK|r4hO=cx%;kX=NN}`4zCWTOXM;5KA#Y&J$<y+SrHF}9XZdq1qNl{
zHs2fu3unQ<9ZBQEAmDAeli41z8Eb(T{nVs(;^*2`%`P5wtBgoC$iL5vEt|s8d&?xg
z#p#%JfQGmt+&{MR2_*w`V}8VTnHgCe<ESP&@e7RJPAK>MtmhBZsEd^VXwcxu2fQ<n
z@&P-B`Q|P=DLHJOh0WbA(EkiCe(PA&KSox+Oi*P@Z9w7{YdRhhiyzOD4spCVpg0Z1
zOVA~npEfy(ER|U#)}QUIdhZ{^Ivf68e|Mh;PB6RQz5?tv36`<EHd%ABjVf+dVQ^mQ
zR=$TUQgi4$@i}2Mt3Q>Qo>(eHp=@7<xp&Xy6}SLA$!!mBaV&4$Fc?$$J|eU~LQ6;l
zn;NRd2_eA4Gg}`@J~o{pfkO$zh=e9~y@7%0$&}+~930bpFrijNUc8~2mGi_?DU*q}
z>Y}olnU_%A-^&^ln3&9Xn@`zqc)=OpP93`94pFJanDyiAtiag?@dp`3h{h<E)Hc!(
z=3o2hmsphP3T|)xGHI}gP+u+-1Q8IoN1FXP?&WJsY$Ss>mka8H^^)j`I3e<#zr^t^
zT6A{KYw?WT!>@Kaii~fxTFZ39w616iv<Gn1JgqYU7y=q0{FBo$dr=oK`6~PQT!8a^
z5eQ0)hi+dyvQNq54mE(VtXh}f*`vlB8;l3Go`y$$@>@{FSY-a{m;b17<Yh}>>hH-?
z?&Q)q$>7pr$4QGmk?f?x<Tcj=)_`-SevC*s)j)t7Us_T&bg(HU44<I==GB>1L4LG#
z8N!)&B&8es47HrBbl2jYG~i*wQsdF3bnIVSuXZflYIlLzru)oSw$cy?%-1sn=<~Ma
zDk9f<_1<80CyU`@W6TYWsyziUB4aIc7FCQu)l<Dq|833zYi%wM0^n#*I;8V?fRuAu
z!DA)9t&(9+FX|jnGCezTDgG1}=l_miVQqcO=k!2Mpno3--3HyKatis*3~o<$FQd#4
z#Y_sdMQ~9WT#-a-rF{XxAO-TBFnrDJ0c~FHLMQF3cXdb2l@5T_>ca^^<1)mBNzu%w
zM4|BQ@+@Gi+^yZ!=&k)Z)~)rHc?9+~&7q~0$`Hf#N%!ZQ%_NSe6f!<m5Skarp=e2*
zESsFgrHq-c8ZLK~&rUe^3BAlW%Fiu7NKy5bhZS18X20sXeZ37bgJ=IIqQJiYf0bab
z{Ya1CF_lbB?m}K8U+}hvpLjeXNk<WVi~Q7gTcDs65{J@?=l-Dv<LPZzOr~UaPA2lC
zZ7FRcoqzi~<01X4(RQPkEVS9y8|Y=r3HVVUHNiZ8n%b~^UHxsh_Xs5pxm1Y8zdL$8
z`&4R4)paPBBMNG{v(k5=O4iYy^cz|Rq<Bs&I<#81#U<7rad!h^UV{4FC`)A1BBN;3
znwhCHDFq+G#v7j1BXg(9t7GGjwCN+CwFFeYKu7T;*mcwoVXY6U5QXTMaES`KtY*dl
z<su@7jdnl~!v1=(2AuMezJY-s#6_M_-}K5@o0pa+zX@!1j?w$46Q4(hhw|q$i#Vne
zda#<JC@anS4(oETTjw6y5dG@@ml7UP+#ox&yd0Gwlceh{EH2N>2KeQoeVb<wyfE;<
zeboAsTT&XSFXqA#Z04J$v$aOmi{s6PTetveR;cdk2C3U$Y(;;pqiweNLC%xoJ@F+%
z`t#Y)kf0+WAnUk35`agcuC1vOjy{$HyV(zX&)ev_N95WzM=>L(si|2vot$Xa$-?@f
z*wirO6sK8#N$qYZW^&B`>5WQGkL4Sr6cC0?)31*dp~m%){W3B_-Ih$EFShu0T1>@#
zs#j+hNZouZ!IDx8vkMa{Pq+V_%YAD9dEbP;>CiwrGvuP9lhz>jZ`X)kBV?F#(ioCH
zZ-hR6`Wx-oRP13Kozb=UsN;c1aw}Evo$gR~=&Es9{JkP5df@=}xjU6|Jp)}p#fqL6
zZcQu38FqPmd5|;XvAvEV)#;vu%bAJsmi6=_=0d(RTg$dK1_!0d?fxO7C<UFqsbRWl
z{X$Hqq@<MaMi~1k7eAz`xQV@5r7O--M-#)vVPdV}X{I-8=JPh5)#`==*h%XGghVu*
z-Wxz;Y6Z>@8_Vm@`O>CxjPK-7%;=!f*W0t!8>wYWtM(2N>yit*u8xBhdf}n#<|i~X
z>0D0XpjEtmFq_4PiuSp}`l<ZZ>O${>d^=*E3}N{GRMGnMQFGN?|C)&Y`}ZM89#<Vz
zTZ1~CMbB<t?c;T|@P>fUMQi&rW^=&PBiMU=ZVMtjEj-t{fxXxizg@N3FgX7GCA7Wk
zYUMw<0PD+Yp4EcKlA}Dj);mt-Gu=&7jhhD36GJyxSU3u>yILv2z}R)g<Byq-2_zv;
zN1&`5u+OZG=qt$NZVy?9*@XLBII~ILzUo4VKG|v?V{??P!RI6=H_ty@dh0=+Sy?4X
zs3Y|KC$u0h11bg!X{y(CZsYyx@{-wT9y~<Q?z@i}naQXIyfmFOkjA=RGg92U4_$jT
zxU3*eP(~@Yzd62MdSFF<<Ma($nOYAK3NfSGrI<r-6A9CdEWOW;;V>pOuP8F-(Ye;+
zesr&gaHb{#zG3bSL$SVDaKYwBP^RHw)j2ix<KYV8nxfqV(-(=e!L)(sjT{pG^@0z^
zNYZ4V-#ol8MebCe8ZnP~?ighfR26_h^lMFHAJJ<luzo(~1^A??^yP{44~QNu*Exj}
zMmVo918D|mSjXs`6N`QbCM73l+Hb+`vxt7W3AkDLoU!0?Y_L~#Lag{Mqz0h~9WgtS
zt4O6d`#5oB0GQ{9>;w4^AZV9rn$@xYRpWuWcKE}s=cH*xT~%z?wsB^%(${w6&efS@
zO!})JS4=BQ`?giNM^=&eI$?I_Ya1_Khp&8L!n1J%)Hh4Pg5p7z*`~RCVxrS_>vh^e
zQctkV&OW$@k#|?AGH?n{&)U0Rut_#A1dv&b@lt&rM3-v2w3xOjy!RnaKmJz^*wPK!
zgWHPFYr+*2bqiX(!x#f%5W^u1?tij)(NlEN&ZrUr6`lI6kZn1Md0UAqp;E2<DXN@E
zMkWI2h@ejwE5Y%$B9g5tFc+yPY-g%)dW%!BAI3H76H#?%X6G{aucvPtVsfV<TwbC8
z&hzPfq9|~@N^ovghWfs75spqe@-3{T{!Onsa&D=)lC?;v-{H(UJ=yT9;PLH}&`1~g
zRhbMftv>C)4mP(csuR0Y-9mV_Kj+##uxP7c1aLI1=XpOXpQo_5@wCEU4Q3lHh*)D_
z*w~c5RNoAIM*d<b{8bDZ8hX%)rq;YE%QV_L>1;}vJ_$;>OdG|}#ZFv2FZE*JvwWm?
zLV~J1Iju{-Nhttxeezp{*$@|MAy&9NaomUhL;(@#y0_r_OtdzLK_rvH0>y68Fz8#;
z3*O^sx0PXm&F-#PmXpTkBzWvTQj6-_|BymRh&04_rGKx9L7uL-jm$w?46hyTZJ2MX
zY5SU<XWCEdDGXP{7|74J^Vw{Zrp0pJoGpqZ)fPbV!EG_Yd|zlFdH)@gm<;XqWXEIY
zn6JCHyK||PlAa-cw4|4~<?q7%*9?rhreor3ZXn^hnM4e!Fu0ePpv2)UI*|&odOZKS
z*+Hy_^YgmO;j9BRk>d%t5*pgak3nSn?b<a62UD@ld@pB>p>c8O_yS%+kkdu)=iKf~
zPD)yGOJ%xFXG+6a1G}78igA@xE2?_#R)blIJ^61zL^VT$jN|?G-J>vK;u6BNVmcep
z?!b|<+4WW_Am_bLh`5gvc(Dx3KY&xg4HM*Hlpfl?UQNJPYwH-vdINuTRk^m!{YEN8
z%-tl&Q)+3c06EfW&waebO-WR|$8h0VNAm4kaeI4KpaVubs^aEtw6RX2DE3(A7T$Zx
zp!NE*n{!TfPNl^Se`M1U@3r9OB!-)rn4sF`1_sj?G>NBsr%ZYBwbK|Q))!#NwcLbF
z$bE0*{#th^o1~<?{zBB!zFm*?0;@4TG9DgN-%_PRw03h*XHI6H{Y>R7h)(`HhA$6l
z7|N=(G$SW7dKRE4m%~Rn^H-@ep4+AIW^(X!^CWEC2;&E%9gmTkxJ=REOZG4^Lx^N|
z)1UFXsH2vI#64l@SFAD>OvlFwU><BpuMEI{<e-NvxFKL3Elv69kGoza>oI#yg5N@c
zn_q7IHz+4K4iV;LTA?0AOZ;dZ&2R6-TW>|{)acKotq7_1vbdj%iOCe1!m{O{T&Ru0
zkm9kLD618doD7L)LFakv&AEGkWudLZXQNBSXYsmoTMKK|YnQ}Qmi^)`%JP!ZBz-P4
zl<GNQNvDM1G|EE6?bt*O5rg4~`QgwSu*w)n94p)&3%0+pQa8j8BD$Bw^wDl^EYf^p
zu!k*ga>pk_v=MG)#W*#tX2f2pAxqHX`B>Ta{OPFsc$4YPvf|Caf#@OY$N_Sr{mw{w
z*d1J=!8oe%vsTP;mP+w9wbnGs6aO<2q$jJe^T}di>!WJqjd!#Qv*Rtcqib{iA_e_?
zF=7mp>uvv8k#vpq6ns}OV(iSeiOH>_t$<7#znpIPC1CjtRD`{kI1XEIyUGq>lhmZx
zZ-D+By-pqIQ2P^#b(xAnd0Dee3h6yy`D=LkX?#CRv(}T~<i=G^w|Kgwj6MjhGX2rN
z%}tif`IzTrlBhG|F)YN*!(emW_uL0@px7<yd{%(*Ta}g<_N>|QVeS61<TlE+O`H5R
zi%$+Ee%oQmxB!RhT`Z5qL4NZmcHC0{Gx?9>nK=gP{-uZ^A&`*tCh8|-6^6^6zBDxT
z7go4|Zw79!r*ak#TbDG;HM<>~SbJ+S&L2CwhL@I_WVBOOlsKDfVf_Kz;&W=FZWr2y
zfvGv8(%XW0(<kp(WHKe`B<$Vm2Y+TU{2#1r@*|6ykSWzs8nX^D_9XQ5@PHvF_xWnr
zQth7EUgPsOp|92e_9*y;)!6<G5vkKh=&||PS;0;85$}+t-a?u}08i-XdkS7(za!hH
z1n>o9CTVo0q9N~)rh<YGjnZ88O%)Z;b4>Nz)%8AWGiErFaN(cL$if^L4D0Po6pMP_
z8L_n8YPh$JV;n8G8Fsed^l(%3W&e&ge!u_>;sT3{k9|yKWtFz4)DRe-y{Z4ADb(jT
zUZ_|(-l>x3?*B-&`UBMb`IYM0gE%PVkS=9KM<Y3gU+yt4Rl|cGR799gD<8Ia#`x*m
z8L<Wi7%U?RU0)(<unayX?r>UYOgm78r}~YQT)Cx%Yj^c{g?M&u4f1)B=uV&YyjyNT
ztkmK?h*~W<>V}&>$5pCPYMqq@52z+0of5GIPUySIP)C$Tg6xq2nwy9I(kD13wn?UI
z!HNbdJ~WZL0dF6aHI&^;XAgMXSxyg(@?Tc_OAjJUX!Q$3K)8VwzCS3Fc4kBXUl0Pp
z?YEgTT6)12XxnQwCEY-+Ek4Cxis(OI`eBitdZI10ebU<eica0)JG=ET@akBZp@rDv
zzkVGAHVz$Vi%Sp6`5*kc2?a^ON78P3zXc8f&`gQa$>gLmy>1mgF!*+&FyjNDp~kda
zylozN^7kh+x;}(}hW7lbw31yC&p%(N2a%EeruuU2qH9Ouf$fyk^IQ)_3&2t5!Li||
z^SXF`g+k(NL5MOAX6s)*d3KgEO3VJuqLJpDyZ(zsBZ_?cFA`0;e>5`nA)7RSJ^lpm
zz?i;Ky<k)V0WninkV&cKydjRz0A;*_nKPg;l%-p`*Y#HnUQi7LAdCStrTuw?pU9$D
z_x}g72zLQmJ3223t}*;whD5iecqk?|mh@x_FiTFfuCmhBegjyZI~}Xd{*KzNE6x6f
z+J1bML3A|Q8Gbt6Mmnvyx`n~a$xi!Y`0n=Bw{w*grHbuu>`>4Qi~6W@^~dq(mC~P2
z5(E}qCX>s*v&jmCdbUY7Om&^JBSwJ*c?H;AZzwq!>x*_YotbFS`3?L=oko7V)^K!$
z2NF}|0t&rmZ?sN1Vc4nq8plBySqT%vPG^Gn1dnx||K4u)SU_J7D-i(c)-PbHS*)&E
z@17>geMkV>#*%&CaRBzsmZ!{@M)1#hOv0z1nVps{_|M#J5mH`SGbd^W_RNwT*KL4X
zd8%-w`a?^fg+MZg1(iU$jdSNAcevfbbedtxe)<WROfoB5pDRsaVG=;P`PM~dKUoN?
z>RFGA1&br88cEUyc*UIk1S){|u)oghax&n739@7A^d3N+E-o}~*^}u6=5|80ouO~&
zWP6{A^wtMHt$fnx@Ci%y!q@%fTl?in$07cteB5#4;Nt4{cOX@IuDu2(jJ!%L(+$26
zBbqyxlEelk6GaL=xdUTZr7G&{d&*N@MvUWjlqTD);UaA274ioFm=zfrEA-<edD=Z+
zcrU3@El>a;9zNj}d#gw7CSgZrnknp*=#_Ik&ps+e8L<9ft9a>9Ag83<E>OatPZB^Q
zSauh2(%7|$8FfGZS~=U+1y^sq65qK-0SMr3ZkjRyf<ho6XM2=FI3lt8ky(;^gW%z-
z5qEN3*N}b+C<VI{N##XO*t2HO_p4kMc<KNBNn5l*;URa<F93E6&;Cp)1R9!AgG#yo
zV0@}w&rXn~+gZjzMOBU9(mea7%Yte-88I`ql+-|D#N}a_sC$SIly}eVhL1s4`_5}h
z&BInAX~yHeF_HGH=owA=c2{VemsTp<^MO)qJJ-*a0>D)dzxcwYs>@e2E>Ip`aSHvD
zCSeG5;=%Wzf6^vWWoBuK{}Vt(BD^hZ4x5Az2=-*0unc*BPS>s%9+lQK)JCUTChne)
zHl6*swUq#<c{+Y(%GU&XZ#)Y;yDs<GcFx+D!L}IZV>09bG^cN$TUexv8Gwtp^VBDh
zil>VYx<iwE`YS4vIDNi|H||dOtjcR}n13hdejaV7mK9y=6p<Kz`MicLV8_$aTK?hk
zC)6>vrq_QJ;$$o<L~?xgKr}t*UYR~+;RB4YW)V!AuRZl1b*VT!h(EVl@$>V;=3ZBd
ztPFqnW^QZIkedD~Jc=7^B&?NF|5yVoFH+|dAtqCP)WUOgFY3q7w~av`Kbpr~{2%wY
z<4-!w=qQ6wOo)UKNx_<?3eZwumQXyO=&&)2wRf?)bQmGh9vDPKOK}!8mgfCvB7K7#
zgB?vr0<ycRh(|PIjd=1YxB)BoyBBYj9dE>q{4qHpz=X-;JP1RwXiJFpXPxT&I>44C
zPrm+el3+O25zXQ-Ei5W7-Z?)HYdpwR5YS~<0WgSGw^eo8zPKOVBLFxNm&r(yzZjg!
zT1Tf5my;%&Z>gp)t(CtBj>ng828RuWAErxarc3WI&CJY_c)ZGrXnwZRNReC3HZ&ir
zo}n64)t)1i5%T2HeAAbj*X|L9mEp+%$=M?JgmE>{r8V4(ZFD_pWh}D(aP6+-$!>(I
zsHC|0&R8YTmA3&p2pEE4_%x4kdio(kA%}{DmPeBV1_q&r3GcbX<HWf)RYU3L=w2Yp
zEod^D9h0*iz2R?5ZiPncjrOaJk8ffuM?-mq<+pX1fq?hYUmV`F*bvK*S)SiE;vS2N
z4P!J@g<MGfjnXRMN}`<P%Fm<;O#q<tU3fvqC<Z|N9d-X|W};^b?qM<0Kh>We9t(oM
zcrV{#m6S4^nJi%1XNzAQ=nvJk&Nkja7d0w(`*r2NZ-kEJAMKhPgJwTU16m!3VxDiK
z3WvUE<w!*KR(TGkg*V{hQZK00)C9H`Hqw_{T1A`JMRDJ6tDdf|iD<Xm!I4S82hGM<
z7#Kti#?!5y#-Qz9b$YnwYnjq(+(*K@Qc|M>>``)W-F8Lp7rg}l{KbfUhD)6(--&8{
zK+FdEdKyGH7<4XckdXY}03i4FaN?O&zUd^wey0+888GG8`0VG!Y&a<zLNFKwR4XVb
zG%kdAIJnt{f#(I9Q({JYjEwOB)vio|l5sG>=_6onLtiex3=>bQI`)Cge_`Foy3A2g
z1rq21bdIwZiw|8QT9-{#Zj}=>c+Noq3EH4ZsTO<J0>Q$N1LsUp1CR|AsVbBW4gNsQ
zjvlQ|DNviyVK13JkwW7ib((3MmC}hLBcnudFN+G%^v1>{Fz;&7Vd%ELhU`YP=QDoQ
zD0gyWT(L6Un@6ow`A_oapB-~S7!-YG^&up~zX70+S$=+&W=2MVAYLndon-m8m$x{t
zeOh7OrMJDpqmyPJ<9ngSvhcY2iYZPRB1@xLaX)}&T;$u)K^zjzh09*T6!2}mMfPAj
ziOq(kg-KUj@<S3l`b_CYR6~O+HM$hwqtZL)uw0c97zlA_nE{FY|5$s=sI0cOZCF6M
zr9oOiN<isUDW#F_2I=mSZV-{~2I=ljX=&+{?(TQ8(|teg`+dG|y#Ll1mjkbBtu^O7
zk2sGL<Sl>)L1AK&|1HCk|0HH{F&qs-4jm3#c<hVZioLFG1`-VF`Wbo@{T-3o{0{vZ
z!O;aH03oWCj@Wkr{=uKx<gXakP4x9?){s%%@hu9K+T?gD(sl6KJ85JX{ag9{!oDW9
z6g7=M1UZa8fPT-J{$Z=FWeAUf5%GBJz8vqdp&qJY@><GZ7$y>IS?v=5kkO+tvxF0k
zu5)vLJiZp`Yvr$y#0N+URZwwoyS*fvblwbRqYS>l4Ao15krzCgh#QS2wsgDLMAl=R
zl&=|K4qHreE}3($<FbxdjASRFCnvAkRPB9yI~_1pCCMObnVXOv0yo)sW`+|>L&nbj
zkf+u@!c<^E;W02SM|1gG+dR}X(hdd)Yd~7h*qGdYDe$@#1_lO=%eo^~q=>{0vPiW=
zaToJ;b)r9pRp(jg;~DA^_7z;ZFwb%m&{g`LGRV~QGanf2>ZP~9$-;sR0rBckbxcx{
z@2rou#L_aRN)t~A<qnfxr9RZ&`B-p}NMZ3?M(P*i!ue$?u?VixGKIj|5ii)2UUk(4
z<7JW4H<Qj#5_y*|ANtC;@N2CoOQhc=)}5gdV8Gg+#TA#!-ah_!0458+LR3Q|S0!~F
z#N&QIW4F!WjaqB(nHvEA`gI#R7GZkQ`Z%FRMpowHw`Hoy(lJEw_)&$u$MS46EmZ%s
z0wETUZx)W}I{D1Anugc7fJ(<=m6-Vag0DYdy24s`o6kZv>y^|F&Dg{Q|C+?kV#OYb
z%O2my7Xi`5YPBvb^GaJ|dGyoUQw^wOF||5=I5e^rpSIAjmR7BRv+U`zW|%U|tfrwM
zwCSt;d<+n<kfJ=+!|u3A*N(U=AoB4V#lV1Sa#~4eI+Um9WP66ZZnPjzHM{bb@3xu<
ztB0$X#PQ;A0C#AQpHAsZpI3gt{M6X|(snKs2X8Xcc3wezey`YDei2RP;kKoZv7gg;
zaUy>tZuPMGu9}8pqlZn3&lNjmdvwO+O<a2}rc*Zakw~Q{;Qabc%#``S1uC){wdxEc
z*?$^_imvn!Wf?-P3*@1RPq)9Aoz+WZB}~CI#bj^5JMAe!A?nEFZw;Y-RB@NPa*w1P
zmcjlKJyD<xWm0DkolP|BQ`hi9zg%i}MUJi8PTNG+TTk?dCNNL0k5)wIV|jej6J5(w
z3B>6PC`VcCiHtOSEQ_ThgxUs5)Ngfz*<Z-SlGufI1IJ1|ly+Yd-CP*NG+ESK``bL4
zr&A%ZhY#|w+nGZ=@Z^v-GcX7$N%za$y7$+9w~o$PGoH#%<mPkJt>Q%PXohetzK-83
zIlQv9nmF{fOxKME1rPrU6SiOX9+!E`1TOmmITA4^ob_5?GjRPD>#V6OF<j<Yp=@nz
z7|38N;T-SpHQDc<Rn8t}T5J22v0u8*5UAYFc>uy{;hsa*tGN*_zbg_o8&mH6WDc_|
zosG503L(Ds^}2b00H$@jf~J_@J9gOIh5EQkxxHWiOFeZHIoJa$UQ7S$uiQU@%%3hr
znm(xOzp5078oEOI&5;o+_JYJNg|~=*J21pQ*f%m0x*cUiVaGo>(D%*kf~I*`{%%0P
zTZcMP$-X!yXwzvL4V36Hp;RdnN>&tLTGG^&-Jj?8Ppp%c{$^ogGa4fqOmBxoMM0Ts
zk7$s%r<53!?Ed~e`!?Y=iRVh@MYq@+At4cbq;2MrmroyIEM5pHTxi#OuCPAqhf(GF
z{k(3Tn7}D4lsvk{k$u7<{$e%i+_>T#ti3jdr;luB6A(FN3wJQz=GH`&ef*nFSs24)
zWTRJp+|$(s3mw+o5Z75VSJBw$7RudP!|L)Dac9TGdM0*a&TF#P6epo4QZP@x-)b}n
z(%Rbk;%mh_(bR5XIy-_jJOAsJFOOSm#`uDs9~{|R^|<m3YBw5iWF`5)Bhgviz9uK*
zhD@9@3ws6qM)-hkqO0WBI4e*RY{N@sE}6p5nV4F*W;t6%$}%MwESxjHiR||)e33;j
zYl?g4snDJIPpi(KOKF{^S+lrM+ax*f<&|C1KY!}qsPP{EJjH{&q|m`r{U<{xh3jFx
z)&Mf2o<E_Y+8X6yVZjQDrt6A*v1YSLg>ODr4-LHch1N|eDP1u@X9m418>3afxqUVj
zTC$)1=3Uvp_;!m_50`wc&<@1>53B%SRcsW8{(aByPn+hhHBO)&dV`}hQ9kZt%7^F)
z2-QX_xoo$zgOX(`i}P-##H#?3{qS_Eg}t?+|2uPV{JeuUOmqVs8yy+Z`bA6}F29CG
z(dRkn=$}NxeKKelSJ%bO%`Zof-i<tGzVvUB50W%e=DhYKlb+~TN>`si6ntmoQLC$~
zOY(CwOKDte?CW|Gg=lgL3c<NN2XpU2KR9I-B_%))_^8pkmdiBJ@cOvwZva9A?*8{b
zu7@Muq1C2`R#*R>U`hZ4Q_@?;^NJrkEZ9F>cZ)l1E!7xtRaHMd_WSG3)Yn30^59-?
z-mW<OZKPWmd-OC^v)D}K!Qnnu)9l{#-3#C{D>5U6Y*zAWPLnAAc9L9_3+pmKWw^27
z?;kAW<m6QNB1nx`+rBl3cURD-m5Od(kRiQ&fS8cb>j>u=mXYg3;k>|p#K+es^jL|*
zFFu|=!S1fi%azSf49fVa;{E$_NGYYeMH797kk#rjXeL<PGIwj=t`S|SF``IQ{T#q)
z`D`lc_``nqvcdkvxl#=8nsIOvJ1k$}G!pt_dBW(s8V~7Z1FhC_pP1*?@U5-na&m(=
z(_1YpCbwsv5=WHT*;>N^O$Sd%<+I%e(@M@MUXAGQtaKgqKa1fpU^1Jnl`)Z-J#zi<
zR!08^E&~M%)`-CXzk`E7D5qRY;GX<4FhYL)!qjdrB~@JC1U}0PO6G=-)DsR%l#RwZ
zdkZ{{Onk{c8tFBM5w_Qp^9)O``ZxBC*<n$Q#DyoLxjx2T9^(y8Mg4ux|FKjU{9cB8
z0l4Tw>Qyg_-QSsooVU0li``_ZSTK&hmL@hD!20DwaqTO3Zp#97XblP6P%Kdc?baAc
z%cF6%ggOhsLS||XJTRcVWqM~?b9|Jk)a1sOPh(Q;xM&)3Io@v6@b<V5>0!Gd87a%#
z-)=y+qA6(IfO5X;{6ZW>&PfS#gyW`WA~RN`K;Uk2OWoyww}Ch5z5q5t3~NA<VD}{l
zpqPWk7P@15;A2|9JMdGy-9g<<{9!zP>j`tRwE*1qh&*O)gz4CXFOR227*8y|qOXs=
zc>ZBT5=!c3(dF}<@l$O#PA_j)wj+X1Cx7lHKk+2sGE=d+ILCPJrisXE!rWpXgPn^@
zt9#)VpFc2~Kc`0^p7u_)ZSosG%hcy`#Ap$$QPD?hD5sUxTU%k{^l?j5C)1^c{B`60
zL6R@UOcJi!sh(;o`A6I3Pz@glWcVqrH%Oj-*;xp-BqAIor#qcP<>6UyvteI)_h?bN
z5<$qh+^;c-h%$L55Y5L*cz?UBZngJy9D9wXZX4U!%@HR&V3#L)6_&O+%qPEp*X~|`
zSfAOT2M%hj_5G3<E@yloqLS4GjUsK0n>WYF&6Cj6gD!>Jz**;0GHMQJ9_M;5^fs8b
z=H{0?k$`Y$H+Xp$#<)H*c(9+!_eI{;V^aKTwr9*?pYg$c{T)FS@~Q)2Rj&#7aa`_}
zIUn;`Dy!cWDWHOL`wh>J1=3`47J6j)s3^r6?UGuTANkPLu2+TiL@fG`#DYT(?7B{I
z*;B&kxE$7>vfkWQaT8DOk(ZlJi_A{U^PwSP(|4`X^5)1_Jnsy}^SJNexs04Iirk$r
zpJ^?aw%?cDL*3s<xjkI<U243Ys)cf{M@gx47T-SQ{4md&@0oP|iYL7duoCQj+kw@l
zcO(ZhP$5eBbLRPttfsQ?Kqm^fSjVQD&n<d}BXPDn+jXdSBweVgWXtg{eNiI7&}R>0
zzcV&p*8Zm#;E;8y(lB6|Y9I$1GL5`sbB3CZ*A8t-)z+UisX*oBG4+P9jTjvYF_+ig
zgvm!k5^fb5C^z(Q=|k~;FiPm$c7%1bNJVB&#OC-&yhiH(Kee$JMovzS5kWcV{W{!#
zuSq5F6%=1*pAsS%)B$a5O#7L7`2zsNxn19DdJ)ac#`KCEe?@LwCe)gaV}xfbJVw#m
z)<f_sS<XsRD$7!=`k{g+n*_*>+6!Wp%C9ev!Jy-V-b>;I<%Tb{5(#3-oDe*9_H8Ew
zaa`(xBu>C<U%Imrpi^S=Rki+19mjTFzlg0v;RPir3x(jWth}5*_cxiW0ngM_((xiS
z2-L7npz=OSOH0>__&6kWUAl-`e`aRT7t4YL-coP(mml)W%FCOpOUMt}!i-CFza!YV
z7a<yrTgV_MuAOxcQoYU??7sb8d=SQcl|vIu`yKM~0yh4IcEm@ATi!l(YiZladAD1S
z>a{C0vP>A%pIP<4R<_45gH#3pl`Q5A&;px&B|5&n*67!!^)3*cWBJImFJ9Ci9noy#
zvtve@?tH5d6+YfM!;`%!ZPYBxkPcL9nu~VXUq8T*rQ3Vh^&G`2U@6m*vQwzq>Vy&i
zAjXZL)M~qBlt-9@XL?pyzCt;Mdk+a@te-B)SnWr?s1gdp@0m?j*;Q>H8+!S@5eWO+
z;{AG8J>#c2`dcyS=4Q~SM7-XU2b@;zn*M|}ptUqdwFVOOEO@9B*ZbMm+ID`*oYw^8
zPe#WgIn}|@Wu#ROy}PNOLA?AMk#|{{IU0k6&S!)IDw3<A)7?3W!O84|9v)#UC<}wU
zJE+FAwA)<iNY8>63c!piUc5<Iav^c=$y7QwB6Rfd?(Xgn;i;)J^mKNQ40u#kX-Jvr
zxQ)ZP8Gyn#K0ba}|JspC_RF~qRrOQM7SjVJHU-XHfMKTvEo}O~e7pB=&8X(-^lETf
zT$G|tRULiqSFSRmw8slV{D}_96J0|&Umh$tU)w~cOSp?PQY@H{pmYh%$XI!7+Wu@)
zo8$QlbXHrc;4d7ln{8S6{HGf?jYy}{Q<Lxi3zvvVjZ0_7;r!Bmuz+BFtQg*H{WcZz
z!r^ETO|LD!%Hs`QiS-qwQXv9dv}~maR)XH#!paI}pVBd5<?dvd<fS`_R|=U_{l;J-
zE_X^aCv3i8W%FWCBf~vY@`x^23@!eXy_u>lKRwlwkHHeinf*j;IhUj5x<NWHU2Yc2
zafID=wWNpl1jl2k)^=vK7ZNM*37B-+d;BP^;J+{>&r@h1Tb6Q^<zhX_o<DyF;{|(s
z1=kzp9#*(_8s)LUl#I%M-}^Ofa6nu_tNM8C7LhYPHnzvHtt}ZQ!Fb$4PI6~m5vHW%
zVAD7pI~{1j&(YL|Gz)z)Da6FYMs;!|#KgtrvIQ?guP+%fyUfyuTfU(=dY2Iq&h_xw
zz8OE|&i=dH`AOz_`W;db1;(JMq596wU7vxWV1kme)1qkAH*exLvI^iFztK_V(Ly<>
zT^2RV9pC4E#fb%0*@kaxBu#7H%LPCU1BYh4s^$C==+?yfQY}01P4c11ymM8M7#4`K
z^(30D`^rkTPa7&vAKy#Z&cO-E$igI4RmdUZH#s%comdTo(&tUZld-fYCB}-6wW*4`
zq3P@p?hd!~fn@|o7-jdf;bUDd$ZINko`wenpT$l7;zpFYVSl4WSp1XR!e12S_<s6>
z0AWFZ@c)AW$se)Z?mY6pJz%HV#e;4;tmL?yt8qpxVY0NaFM<#M;rVY=DE3pU6_M?I
z*D7I+8Yo$*W3v?x*DCY0y}c&Ql~X>;sXK_;+KEUJOUr{&)3@_jE}PpFu|#AP6j)Vz
zbAD%;c{vJQYIFQIwG}J&-=Eu|om`<N3uFdLY|iGFmU`cH^$p>Y^|yzAn0_N7DyR=J
zt}<JJFYqTfBIx8xdw1SEs1b{yfb{Kmas-oi!t8ZL9vGg0n#fh*H__;|-%#Wd5bFSc
z-%fRuSfSo9RoY)Tdxb`T;|E;bQmLL1s(v|W4ADVhk}vUKokzcHz=(?GK{kEt9~~8F
ze6YKcTlVJdTaRwogn3f+kMBV}X3BN?bfU~UZ2MhRp;h9=34_?p&n!s%o<%IR;Tw2R
zfGa+J9`SB;ElsC>!q!`25~0h7C)L2rbM(X044?Nu8q^zp;2;sRK-@xjTnu!;{JPqr
z&`5d1<t0Z=1`KY&JnFDRS8Ykp+4cjpbo7kiN<<YCf?Qgb&`jf)!IZmcH`;H{*=`$x
z=I^E`CUT03P|xDV_RS1d`C@TiwYw3YH2d~XTdYsw#l*(l7pBQqH)0$W$ZkxMBN)eX
zWiZ&CS&9>>#3WU>Urz66qO-E;WQ)pFDqtq<_7Eg^Y7y<74f@`v&V0=?13rw&Zm=x-
zT1GdlhjNV>lxQK-d!q&vsxTRXF&wRWBWd#nO6X|1f{9=bf{%BPMh$_5dH?+|np0e_
zY#4<^JIczpWOrZS+W<yjs)PPgXshVrocRi8hIYgs0yT+=^qrwZS%uRL24K3kS{hN2
zVVT|G^?CU0X7kN|VNT#o237W1U{KECfT5#xhT{dJ+Y&Pv6sj;D#QP<o&B^KV`{!_D
z3+0F1h)({ak6_}y6Cg}seP#1H$QePfz50-Kr1>qCHGvIDz;nV@iRk&Ey={Y1?`BT1
zZO$bpE2~6O(EpVgF{&BlQNKDkVdK*t@f}0sqN*TVO1?PTIKykieSxG_w<3m^QebXo
z`@85IVF+UbU%bjHe_EQcq8qz6)-oqgsM$9ql<~|zG{7szeJr#)=Y1^g_m(*#rCC7m
z?%PEt#jxlgOjXJ?K7N)L@;Vii(T{uB*_*p_7MlFfxa`x@(iTCmIa4yO$~LZqh}gS5
z>;caCGESVjG=BaztvyXx^e66ksDj#L-1F-+8o^bXbHULE*p8Baynq$I_jo1$xKU78
zvHld76>BAWU7_sqZe(~72Q#47Y~Ug|r9nCT^Opt)<DcjYb!rIfk+hCf5YHgB!i?T@
zS0lc=kLjU_zO7cbt6<v$cQAsMODYhXg8|-Fvj^X@Gl;V&DW7hwe>5gh%val<bismZ
zS(*b(%j&><zK3Q}11yvFr~`W>ZIFCH-0I~r3mcnXnG8oFWQ#UQc$nfg>i}o65o9=@
zVn&felHVl#?uzVbCh|kXUjKbK8>c!RUlhD^ZbJ^7U&=VmFEF1T4uCI5$hm|l`*bh3
zSHWfBd#%s)T#ajl>S^8VRriDag9roNA@+4kMtRpe7NFb*xu^_U8CZnloCP8SY68B!
ztE+9KjAGkFqhWTqXfiCmO7!<OGl$%V)i2I7FD(!C|02(tMQNoTb9o`&nx7nLV!l#C
zpTUAy1pHvnF{+XV8qW2ThcB`u1$2sTtb{Erp*@cjQGzr+-qSY>@AW1A_`5%yNPk>n
z3Z!%!lC?h}BdIrR!w=zZCL>8;c}i#XFo?CIguI%Bt&{cVjl}`$XSc@44p0lU4?eB3
zTmMLqxDi<HkFU~P?#yOLqhEjU>Qxw%^C{%RhrBfJalRM+$?p7XFP9Wu%fdE>Lo!!z
ze)9H7ebztD(Lmupn4XM-xlqsGguj@c3X*=7smEMykbYs0N1oDl`@lgGb2vfXy4^w>
z7MjW2x3~4jY<<mJAUCVO?}@T<H5v6emX=v@dY!DQH0tAXB8__AhMXb=DL8<qnxhny
zi(w6egYm>K^{+2bRQ%F#5HBG-+@rnyiK1f6*0l`gD|uk#^v7A*w93fHAbIfugOZZ6
z)+WNVgG(6Us0bRdPX6-!9eTsR(m5VW-FSVP`@L5#`vZSHV$gm_A~ogJ0$nZ0`uBg2
z=>Y#QkQ_IE8v8@^gMyT*k5NgX{@w30va@l@dl3!oe|Kgu=<Y5h$g=x^P>~JSol9~5
zX!OJX`MCcm*b%5S6|2n{?2CXCLvw2Y>X5R7FE(#k9V!{+nivF#=zhQPgP2^k#RX01
zsS05O@26|OBSPI<F<K73y<bquZ8m-*A=wr@!o@hA4wXQck2tfZ#Ef~Dpxe<iHVHOe
z%)loc9W&o$zLm7a<Bt@ao3Yf|ZTO$f?W9Soe|q*DliL64=uw*d<H+7GhlAyx%DD@D
z{-Uq`0u^8_EMVO`MxtSxE1a-gIJDRkdN{}cP@uceryo$O_5_Ro86bjt<@5QyoGSFp
zDuRRiRD~Se1aGz~KTLMy_l76MdVHvU^CTm1VJiq3W^dLV4zwG#_$Di)zRN_Yww}NV
z2ngUXGibSv1s0xO@Z}KF0J(9UsshN3S4%ap6o!VXh`-zc9zcUm(PyY0qL~Pr?<{vU
z&4cP1Z=d7RL4LB%awqNWlt{`0%7P>?J^0LBt&~>~CNK@8dpW`XZ{j^*%H!`j3I6`X
z>dltY1b=1}4F-*X`z#Ki36OfhrdVfJ0c)rq=n>W4-8RgTF9_VWyltfbvxp#!<z2nX
z%bD|)u4sX95R|ckdAxmqB7{VM1O)|^@Ml*K&gy{vnKDahAKYVZ8_amOJC!Kp?KAYL
zO4H0jjp}m()p{F2S9%HgLPbb}Y^&!j?&{V?HcvYd^I8fP8OvywDsLi;8QH0+@sg2<
zAe^0@^Hoc#aSeV*{k&QH^!jyc-0OnDX*$}L8$Gr&HTJ|>i{a<zZD+b*?f^d?+(7!Y
zHEp4;o?n1C*HW0u9GtimjJ;fh@RQEo#3tg={SP(aOl}R1*k@_4rAFr9$qB0X#Xdn=
z5AL;msHI=j-g#ggacw^nNH_!_{AY8w+uOQKhw~xg7Y6hKWfMI25f8vjTWmj18vOVm
zSG99MP2B>tMtJobPnb6^rgt$}cVas77|gvJEmD9r<xxo$-@=YzF@V3<U<(teHb)Dg
zdC<S!?%i7qI0i-yt<eZE(rKdRy<koS_wG(UuQi#@c}7r4woUbjs2j)2=zKK6A?Hi>
z-(oY<r-g<=zQzT1Qbu9NamZznN+kyC1Or|Dg`_?H$!Wor936;%dB2h>9(c7l!gX~}
zHD7%~CE{`O3|viIQ0ycPi(<%{936TCV{a<fpXx99wZz}*$N0K*dI{aU)f!o$FHFxV
z7QLyKxzV#;T9xVaxB{Kf#u_YchjX-h@~0c!3mqRH1`*L3Sj{2)!V+E<q0Y4dl|bj~
zusNg2I@KGgr{H*cdtL9AX?5FF*;Xb_`-Fnp8uAZcK#!(H7s^g}OpLefmV1YJ{M~D>
zOIt?0Lq*vldAZYy%1Y1kn0VTW1Y1)Osj#xj2ME2;MCVl(ZMCJzG`)d*9bLX;=0$6N
z!us#1==;w$wSb0ZspHo++E<>#U&8k<cf$r7>;$N#zk-?{g||K_Y-^hqsekqfhu4;|
z`mrd-_O$tH1XXIOoTesPyYS->{PE~lT9$KJw$^>IRk(9F4CGIk#b5%r#w~?aRqI`t
zRBdd^#TZDZlob`52gZd$weFi;=G-OS%;szSGJ6{%HYl+B;;FZeuEO4^G3n1>ip4U+
zX!BaGuw_>=(bLguX={H<56CtA234)CaN&2iqdUL^f%wzb{`2L2@O{J)>|}d8?rz15
z#mQ9DMLC_)n34>=u0|{kJioG#(CHWMBEs8gyy-vH@I*i_%>6s!)2Ggn8$srAwrLA4
z!Un!pIxNQoa5`)CM3)WiB1@jQq~$)d)+ctl_BOPFwK+Wm+(lT6*QFlA_{HV$YF>9=
zpMXr55a*fRzcr|13W6o9dMuIH;Qd98Cd~v7mU|!Z0{~&~hjTn?GrOr0K79%d4o12-
zEFUU{o1Fgsa{HPN*)KMgNgytO9HL5ZKof(XJO{Gfv7o8em<43m_ydu;Wr!3?FKHo<
zcVe}QhJ6OWFqh*4G>&%9i=M=W%S)&AnOvUwQ$m5|&XYyu2K?(AC{nv)CuT!`pi-u2
zcObkUN_j>`o>pvrr{z#-7(Vfwxkur)7{=1l68D8Zu7D;0yV;g*)<#I5cC>dk%}Ec*
z4fv3dj>~XXs|SGAZ1jfvcdgm;bMt%L82sjD>DVqs8(dcHgl+qS>+r`nN`E>-{wfE4
z-{L$BsHHg5q6goRM3<OfJL7=y$fD!xTU%`n`YiR+7vi?Pa$9VqB#esc#N1B!OGh0!
zuPh3Fq?sM%Oa3l4TbwXAoaKA?lu(b`uEXl-D!i!Ai>9BM{*};-8nYv?Qm0m_i;^Xg
z>?NV*{8ibR%a~4uQ)BjBJ>vifr~&q#yl@@IzICm8t;6X|x=~faCWhNG7zqX-yf)!b
zg|Kh6axd<QW!Kpf8G8XCYK@O;);p9x=+E(?U|pU}C$Kxhym}=$v`fF*dn1r->Tdor
zGY~7qRN`czCIJ^07x-DC10gXf=8-znC1^+Kq2dO-1pTH!hq6>ufHRh##qvMn2>v?8
zJ=W+!pZ;yX)6ek}H3a4C=Hx)o091=bag`4o+Mxpt8Xi{2@v#m2<g{^hkmlO7nv?c;
zF!lTC%CQlYyF_YCg!cB%)L<{KnU*}Gk5N&+{{C+!CnuXnnGG7%<?32p)>sU*I%$lO
zgK&!O14W)UmC%F;Nq6bG|H)YfKKm_&PC+3NR^<O%0EKk;LjX)b1c@VBTwF}^Xo&+<
zgrk_;X5hWDoB!Q-@0H1HC8ES?PnukwKF6k@2N=3?ty_e-!P0KFWMH|%vQ`#D+r)$s
z@o8V8s_I+C*7OC79?!pQb%APNscBQWvcNL`CEx1heoeftcYg;uGe4Z~|8%teeAyg?
zrpb6NnA7BKU1`2{@n{aqJm8mg)dxt1un)Jr*0lBi=##5=f?OML)>&-T14AUoH-5;-
z$dovIwMyWymbh0`fAp&qTQ2W$o*^PQ1%EHYApydwglkYKsCBd5uv`KU`-c4nK}^HW
zU~|y^S9d`Z@J74`Q9g?CC|f^oe^RZ`E-r;S^SAsUtZ2e86Xeb~I1)Cm(kj>jd6@W*
zYQ84<uUek-guX|4BR%m_ZlAj6f9b_OJ~<KDP_y{{Q$@n??ssv&kduLwg`Ph>?00GZ
zCb{A2L*c>o@`Ky{x%f9|OpnmDKewC7g`~-c;G2#W;>!ujVO0dCDW?|<r{1wDi%`=D
z^#vAaN5s6<6|T&WzaBiwIP0%v`$|E2e3fK9yXJa&Gc#@N<VMt_;4`gdxo>6vY^ZQc
z+(=nJ*H_oTV7bMM8Ni6>FYdPzWZg#k`UtMBvjhG>E$$wqNg_zyqVOD-myfDNX=~e!
z<n55TQ*a?VWfLX7b@P7U&ew5=lH@IUz@<$KouqcJ3JYIa03RuM?%{A8F@Hbp1w$MM
zfF&gB_|7E%4lj}7^eBac*|K|>Vsqt0>7<t{>mL&2Cz45X=-3_*)}Eo8u@Mtp&@G@R
zg>J)#;PH)Ak5Q&0o(u^1SE!GD&!^9q3cbAr3hwBh^YTJ~xQ}OM?9)F#+MjmI{bV%8
zYe^RoLcWZ<mh{Pb)2hc5w_jDE25WIyOdbG~f#$NzDqnPix3Pg&I$K~TUe8pF^O%-v
zy;|hE&Aj6gcWcD*x9UXETq-dIJ+1M16{fFsF96mM<teP^)YsM5p1U4ov~0zd{qlJY
z7mLu#aAa*^kKg^(2;VDi+fBO0t3`tZ4uYpu@^$ja*OiNYkkd#AjRA%u2FpXYiO`$0
zqvCcb?@rZQZWzwUceV+uiIP#$<4&!DzN|l)F=DT3wxeZm!D4Mw#>rVm{+ER+@(8@#
zULREw<Idl2DzeMv1{XV{D;{<zKjyN;9;`a`py48DP~U*tTf--#IDwFND<k5%oeEnt
zKbc^Zxlm|W9m8M3EPEDBLq%X8vGnm%EX=}JSg$g<@B7mY#OcC~a+_h{iHTl<qK(b8
zpgg-Ml?;!J^l7*X<ZaK8Zo51mJG*)}c=d!cYrE0A8=gROtSA-<hTI*0&;5l{-F7UT
zSC71vGt79Fq;|Y&#NV&RPrCF1H2_$OZ8+<j@5FPl^kAJ;R8bqry;_KND@fIsO3TYX
zgxO<k^Et?F+*Kox@wBH!)U8;Z04(#puB`Offa)eC8+OJ&?A5zYC<m_bc7eUnp^1?;
zKR-6|=Pc5vi3G)JymT3{5wx9bj&Jdba!HaductfdtL=DjdFRB#V`Brr9^RLDgwDNL
z+Y9SNcjbb0jr!O#GZPC2dEILQ_RKFSiKy}N2bZj+jleuF&&sH1RDrjGm(%)GCI+B1
z{qq!xdN1Mk#JvJam}={1(A#_)3r&_MLR1#E>d<XBM?1X_%-hP;)n;m}aqRbeQ?0Y3
zSNJ6b)_9A43=|QuTOHSR_w{&2W>Ux(oQtU;TPmNoh4D)73NB{iBzIMpr0dRhh$`$~
z9FA3693X5?oPikMda4OJ#uOxTvA79={-d(gz_+hj!@8IU=pb8s<?<nrQAK8|4QVUQ
zrah{JQTgj|rrtju6#4T6`j553h?~F4hL-%%f5d=cL3s#SpsRhc-=l%$wBBVE-)Jnq
zu%v*SRxN*f-(#@%{G{itK;{aJ{n%Cq@0%zp_p6B$Ux16oH4t77-Mn#_<kE5(L3#5=
zwBvf2i*Ym$S+(G|1Vf@PCu-a$N*ShT*%tF|Yp%h>Y>!AuwLpIWD$!n@&Q9$KyYn+N
zM4Z0PhJ84?+ilU&Tp0}DvJ`f3c!-32<YoktpK|0`&Nil&=kNl&+n*r0>0t6+Yd-oS
zXC3wG^qK%3sop<R6kGE~l3<}u3*$$B?ESRCdmrGXu(j?`jqMh8ab*t=M;;NEb*JpZ
zq$Yp8UWMGel{({)&2yKpkV>JFZ<;~d&Emqx_$bn6yS%<3xM35pCvC@u5yi_zv*)@4
ztz;Wi2x4#xqZ{swt6pJ<3cb#EJktm+x2=gtgjUH}1+PUGDOYb#t&jA+r^VyYFl->6
z;7a3R5Co+xsDNJ0cb8>9?My#kdbC11qSv<4-yK{5sGPt}=s)C)o})enA9=J|DmSvt
zhxy^-5L{pEK~n8zNkjafiH7eYtdDTkH0lFuST09RY4TXrxqPgpNlV>rMO7x_<9aXg
zf&6Hy!f{uu-D^9$m9k+SqGe_l_+w67OGhUJgKD6g$@vB~)jWCk{p^>T`m>{HKTxE7
z)wHmT;N+C|t*|xw5@;lsxbTi=Pqxx&CI_8=VPnH%j;Bs*&T|H%ku3VCYCiuX#8PY-
zP7e>V^Oh}=t8uYY3=(e81G~lE$w|e^0N9a$mzGyJ(+d^1uDVq>uwmWy3`Li4@W>HV
zo~~>rLQ+G>AefGtJJM=Cr4e?#Kq+;G7Mh0#lzLCAYO#;$gBOqcw-`^Ygf96~{cmh=
z9yRg7T;(Qy&YdbZgK*|jG0c!H{rOJ*eaO7@cnz9Fa3H1UYh|sY9KAZcmVVHy2lT7l
zAgn<10*9;H{H7n6?v!RVKcFo6rxze|MkaH!1Z#12jMH2ac&Xp?IqY{&KWFT|s=>v_
zYv~?(lNAKw#9ztEGS6(TWDTMrf;n~M&!2CGPhet<evy+I(9tpWs=ji}PU+ZKP<p}F
z{Fxe~*m}*(rP79Cs@xFXzN+38v&y4l{>HnGH1*u^rfTSp?dG+BLk72{%XK@o-ut2?
zH8A_LaK@O%KVp!KUH$x#;q&$_Ee0M$48>D3GCzVkIS(3E=mTSvHa9C_3O#{kA$2qc
z^`A<NpD&+EkTBFLs21H>#0La0ac|Wu&s_8dzTWTWI{(3?fwVafC5}I)uu1zawfaE@
zCv$9MV!=pMhoP!?w4!K+2^?}mHuHQ91|$`gu%o%Qw&&;1^_XxiY-Z_#*5;W-wJAHV
z94I>8_4oG;HEEb%pN|w(I~-W$dbYR|^Mu;Y-=H>K7Seu<YMq;tFk4GUrJ{w<KDiBa
z=DQkn6pLXO*NOf>UZ<ri%X*i)p%P0%%MHPyM6-^!Hh@Qj9x(KgQMO1OYhXYE|E&4n
z_OAD#yEk2Gp$`+HHb_A-mgUJMassz23NnF%NTl<k^ttv4>ig3KoXy&?*SfO7E<ED8
zzk8Lh_tXWI<teRtG>_<&nY(ryu1Fyx)*u-c+P}Vdp6MMk)!T~!Vh3NlxB!tJ{$sZP
z5rd(Tk>^x}QFkT4m;Mo*6lx_UmWpSyl0f4S)Yr#GA-Yx>m@dtfe9MoHjU9^jVr?-(
zX+)~6Loie!SJp~3PoDSi_#le!RzO*qb9iK=#9+@&>6zIQc7Ob<hpsFQA{cN3NDX0q
z&S$HSl(f!BcRM2OPEm%T_`@TTD0&a(34N5}IYmemk2x$B;5sE@5bmJ-R&j6t1@AzJ
zL+V+pN{{qOTF!R#PLybkBp+h<j}#{nReZ~v7CpQ@93$~pEi<^Sd8)A)R%5lXE!=~g
zmy}(;Hxg#jvg2LvQtf5ug7}*Ynfu{KVfV2$cWZ;u-U8XIJ?T28%7=*^;X_;d<@TNV
z<2;{PLwsCDVu4RFVZ7h{@;s5LjmfbG>3BOazN|`RA{5}~h6E6XNqk*mOT}rs0cBsM
zd>HATzs_v3zNL8EVU(}jfKqg_7m^!6^|E2D)m6~l70Pvc*8YL<cww}$Y~Bw*%?P)C
z&kd}{L9LAEau1*j;&V~9`?%_LJ8ijfh?S9*wHQ$ov?|JMvp0@cW+2XA5LXz(XAi@x
zR*n=Dz4GHhp>#U_J+Ii8nM-o27?)C%Rg$(FdX_CBqu9h!x{Y1(Fm@sx?P5+Svp*vM
z@o{uR)=bdrcUGnKRb>_QQiBBla&)fX4E0j?Gxc4Q(@1e}vJ!#VakQ4VwgVHTQ%T+E
z@i8$-u+Gz6_$%~zH+;E{+S=M$Mn=jcC!S6WX$7BrVGnYriGT1gQNx3_W8eoFZbO>j
zq~zj){r2tKVcGj0=zLpE4rbkK{g+q~kl|#l&Ckvj-7li?I4;$^y}dQBD(6XvLc4<g
ztf^)ndU|<*5m{N&BoAVhpk>Sg?h3Gr`slFC{5o2CXO-4CIDRU+K0vNgpyA@eB_WNc
z85?Osj`UC}D=QU<r&Md2TbfS&pv|3|>Onv&dfwQs@k}=NQ~XhNaQ3((r>nKj`oz%V
z6|7gr(VJuYKM0_3;l`Dsp#Gz%_zihCyNd!4c{hI6FL@OV@1Iif#=PaPulpajlmdPq
z!ioaEB=OIm^B<pMrZm4GY1Z6-u}^VG{ui$QX}|yd^66XfKYsF_l=vT?{E1N)@b2*`
z-ua^o^k04F-zk>QPXMw0_O;2cofP+fY99&izHk!ldzTA@c+^M{xeQ?m36!N}jPR%^
z^^6@$g@?0YuQhGDm(@>8@}ofz;tebcITzPeNxp(ZIPk8La+8%>*an<|rUrJmC7Xbo
zq*E08UGIg>iWF_W&e*awG;C~j6XI{@?TyBAtfgd+Jo2fI2x!rL34isqU*dtryL^a|
zy9McbE<F_efvd+Dd@+7S6Bn-^`gPb|nLVWxi}ecoLDz9Lf}?qG$O7!O<BYw_xl;h-
zxG*FS8J5_{VP_Fu5~5QFaE8zp4dBJb#&9@8fR`4L4)lNALmQwmmA!1Z{IObC)S9ga
zdx6iRPv&+yo5SQ#v|F@wbw8W=HNTX7@*U}QqhtK|hNq{w_SErr<!M_(Fb0He{b~wL
zS5NP&RxT>hOP5_@_o<X#=G9^Q!MU6B4tt#vYxkS}Gj`V>#F>L_ZWBEZDKOj3-&|7`
zsxk1sq0f3dV}ZcNqrYSq;aII?PMO9x6`0VM=6)g5`pM*<Lfs$tM=}IZ*Z7SzRh%pb
z-$qLmOKe!P8rcw{3st*HFbwo0RS1m5a9=#spu5FA(r*k44i+<+-YC+F>XJE$QZN=f
za8%0fkmdMZ9gpevxsN%qGg4vAM2_{^Zm-J=7S%>w`@X;RVy(!b!rtDcMjJVlkT3J-
z@e~Z*wGAt$y^%)7MQ2DnsMxK-ooofueNPVZ_Rcn^g`J3*uEn2FQD_|zPp@+G6`uJN
z6wt$<Zl1k4it1Q^fV$Kic3!rL+mvqH8m4>Vc?=-Rg7ic~`>vA^jK!tf)6JPnOgXlY
zSFLBl;iX&e0+uH|ezjt_3m|<Zw>o>R=L?^WecliR;yd<)*WSX#I4@d@=E0+AuLh=>
zS);{1KAg|DVR<CO{B)c(qR$lOTks+pxM)S)?S@gEoSH+<ai8dMf2h(C7dzgCbLHW2
zad3D+CSxu6a1ePC#nsi7+1je(oRWchnFZ_mjJVaDplV_2MDyH%Ei&7doQ#agen9y7
zeiUG3^^%J`?>zX6%gb9+AYAt^7jD7)=Qf3T7eAWNP~a%?OK|#H8o6&Ig{oF()4I)p
zXnC?}tHih1V93bCDij^fr9C+`5ovl|Yl-OM%9bXPI2FTqYw9qbmshT&tla#qq%^^J
zO~V-+s}SX;Bab?EgpuYByX;J+8xf-!G$Q5~TcOK<U7l<$l1iQJ`dM$AFH&a^LuI61
zIIDI`wkSF}9>pFk5<ca8(}fcU2z=9XTv@jdkBx+;6&1}_K8Vf7aMv|hTgbjMZO-a<
zC*$CNPvorZx{By*nduYDYTciA$JN)*nylM<z*%nYcd#tfGB<~^bR?d5NCfCjB-`29
z{kE{ibF&=;Tmn35>u5dFr|U337*u_U#|wNL8<U<_)ZTUh1NiQ&R9{?~RAq(HVhEEt
zs={SQ$81-EV-UK<Hs(~r5dPb@Z$+ll!SWDLMp)vS-=Ef}Q)d?z4f7n6zlo#4${MU`
zPD`f(oPvkmppZzzWZC(4Z?tP5jojl%C+uJC9L*z7n<HA38!OJe1-7{?F!P#j;J-0h
zzMtr<dpQW@7pB#)hkZ?GfuP3KAeFLXIa96peGw`-TDol*McQYWr=9mr=lAZq^=)Nh
z^Ko;Zi0~>j8$PzPo%1Y0#tyEtCkIkRtTEq9xnP`_87zB28#bCDfq>NZ(BcDT(<xkJ
z0@mhJLN}}JDcdc}Q&kcHDci}RmUF9B{KtIZ&LV8w+>oFVt_L5$ziM~BS94*`22Xwr
z##8qayD`FxM)wKt%@sX$6(nWcCyRQf^Z>N7oSRL`rii<eTMejJJHVgtSVMJycVVSg
zt@<1hWck6|PTdmB5%C~h!Z_YhmzyklN$QL9>kGjwVOX6}kE6FJmNc2Eai%JbP?pl|
zf(aj^)6IQ&GT+X|h^!byC_XfW5w&d=HMQlSn`^hsgjsH%8(!}(Gn9&Izx#xwtx&k~
zfgzgVQ>b6q!>4UrcJKXs)sY#U`kWmK+|8MdCSMwk$g|sC5|=w~V1+Q)_P~ql<jED$
zK&_CHrb5RJYE&bEh7Y_Md%Hq1*UgE%pkim}BM9^J6MO#;`*B5lp!ss3+HtG!xulZo
zM31)*!u0Jm;@B6?bipHiA7zooehINQuVpsP@tKO3Yt#0x(J);Q$r_*;{>M>ze}0uC
z?&}sunKJ^*IF%$U*|GY=FABDvaHFeD5=k6k&WquPPmBxVYN$kxs-o?`gZ^KlQ;A|G
z7GWbRq43o&F)HbjvojH41VxFhH92VCn`(czyx#qeIctFLAM4kcbN4UINyApWy;g+^
zToe3xQ5~>x9l7epTQd>k;1{)II?d&pobU>T;6h4Dq8{&l7f<>qHxXn%kKClQ*XVWl
z<V#GRb@mL#K;~>%NC7ff8I*UQiz_QXF`&B)xW~rDb>DoSntHjiJ65h>S*!T4A5nv>
znsylHcsG(@eb;dn-|k|^2kzsSqHuEG=H})H3>EILV4BBV1)bA{kS&&0@R$v^Gk4Xu
zoxLuJ6sz<FzwtUbS%st_*RU*QSlwI_Jzpz?^BzpR!*jb?bylslffkQj0j4HaRv}P&
z9<EqfiHLaQhQcH?r+D0~>}50>@R*$2mJQzmf7tVIUr)I4!n+L|F*kQlBt_%(v<4a~
z*l#Z?TXO956p@dqhxSfh-RN3OgC^mZJm&wlXf?sp>(7iU>mx`=O7d_FQqVq<=R<PO
zYZ`W*%BTXI9la#1d&MaZUF==zusk|K;rM9}D{#Gjj7fFoRoC-$M}&cK<ip`7C&$IZ
z|7wHI!NK7l80f2#IMsuOifS)#8!z!H*QNV)filbL8}#asI*t8Q`xEZXG{X_07)H19
zQn$BP=n&H&vRwOcbOz&VgOgoH9md=<i`FyJsxP*RHa5ZBO8L7|Ae7VFM=;0yKIxC*
z4edLLnZ`u>G}b4~NX8R4-lq(eEjYB}Ads_w6mq0P4NS*;uBcHR_GX$?y+dt~#q6mh
z?0l^)EFjJnhgWIg>MhU{IU5vb7`YujQc8aNGGgk_GoB;OT&*$lq{DThBV@Yn>;Y1U
zm@Y{}wOicO67Rg<D3rotsR5Y)(c*RVB?HdkM2Xn1s>39Ck9v0kFt6RyYOd-Juq-kZ
zLPi_lQYVh@)N@@95ARqb9c1GIiPZspJ(}8_zipCeN6A~1C7Q1XT$MvZ&LU-RI!Gjj
z0(;xrA5vdPe1w^=E;#Ph=zf=bI8U>>q#aF$HggmC4B$8<8biLcFbBrzgLLQpu^tL`
ztCgpAd*h3wADo;H86ZC+N2QU_?fwvLK*P6_{K5IGLyAtR_BD*BAOebvjL!9SuQ>$@
z7r@c=!`7PN3ROf<A7f+XwjC@HlvadM*xe8!C>zN^1XPNJ*JV;iC<aGZo}9I3HwFE(
z@X*)6BQ`vJ_63GS(o}~`?sv<BxSYBq0%)qyv<L28=yxZtWUp>aapn8_uM*s^E4E&-
z11kGd1Y**Mfq6f@UvDOG0EzR^*D++f62Y_6kMIK_VQKS(fZg%(F+OWIvbS2ji`uvz
z=tX0ugLJz>`RZ4!q@ofvV%FoP{DNP{pBdxUzKD#T7K1~tSRe?yzr=aZ&0APtNp%4_
zcKBt+XSC?(XsS>!!utIDp}!6M5~k&?XaY%rTAr^7M&Xj~Ub;Hi<R5Bxcr6Qv_`)D>
zwhZ@(WVt@wi6gR|wKz>i^!NAw<k3AGjDc-1kksZA6b&#siu;|{`|oKhGnGpoR%A{4
z8E2heZzPhKiSALSHD*;|cRYcGZdGS=xby*pOc6{HDCPna8jUAHC#wzfxEE=M4L;jc
z7|uSbyFOiXbK$<7NxJ&bcCFL1T!+GL2g$@#a>xLESS0t3!*LB-Kzug1C+PC^;LO8V
z`#o~n(uJ=_Ec3ViB^X&t1G67LW$FCU`uPuthMBVu*&*yhbA8%t;6(<A&5>j)D@*+G
zk#trk+unXb+QXLHMwYWw!!&+m9D`tj8=-)^<Hme@&YN!R8Hw&*ajy4WRmF^~9km1e
z4;+sbTyNRz^%`bG^ayy2*gB(9%Ge({5hk4u#EjMY4QG{nH0K1V{Qe`g7m~zHFZ9_d
zC1X938en@DXKU>QK&!T1&3^~+61-1LH&@`L_G&EVudhZ%My}8BI(Dd7Sy9M^C1tY=
zr?a3hPc|}Vnr2SqC<p}?E<_cJ_pL9a>PvKlx_LpRyEvQA1cOB63ykR7Qzht;G#uT2
z8~uq*0<m2HZz%DuHxa7U*|i>EWHY&}JXBH`Y(oZZ%@KMhYqBu6Drl%3Dzzriogswq
z2H7;F@+-R79&-!|ZXtu%{q)=dH8}bd(5{gKJ_ux0MeG|lF7Z)l)U*O9S_j4KCoBfL
z+S}*GVVBr$b!X|R(Nv8ZRR}ki$L%pCd#TpZjfbC$WAgS-isx+?9Y@bV+1?Rfg!+L!
zHorHr^vH9Yh{Mh6d0)Obq3krbP>rNmAJ2hC+{^0c{?NZ#E>f?ckF9!^aDQN2T6`-x
zxDRfEli1u^3zCm&aT^{U0k#%E9H>x4=Q$}K49@R$QMC@Ys;)iw>=bHnqLwhk%);W6
znJE|^_H;^M=-5(y>NFjoP(ngl8Kuvk-K*%%;y-^zvb_A>LduYBtu&y4{^L<ixpmW)
zh~DkI-r^wDuu?GY$uqmXDJ18*G(#eUvx!x8?kB}+SG((zsf5_iVlsQBPJbKx<&iB$
z!p@FsW@g5@$N3^pvxokmX>2JnHnVl7nBAd<Ym1u-_Gd7jQvVPV3aSOvlQ!bwVw%cI
zNBp${>cc&eNwb<s*q`3X;oxl37Z%7y@Ci_v8V6#cOGt#GGA*Ygmy|j=4F_;<Q(<Lq
zuq48{O<n{NC``;EJKt13y~qvP$}?6m5u>{|@S(TO4cR`u`c*QJ2Ld&K?LODa)zrXE
z$qcz9Ywwu2ZD*MqT9Yis(9b&gcYo?nUz!^WG7h7V7fWT0@+T|sf1bK2<$z9(mJhu7
z&kz1yu-qNspYU~P5LNv<`|$tr&lrdI{7F7!W(s%YpwtrkG_QXQEQx(SCun3ub4tt}
zyuH2sJgLTJB(cc?ei1!9b1R`p0g##?7(21ZSMXOaC!o{09YLcriwo>6Y}nE)wKb#l
z+*-_e3%5(d01g?u>iJat7^)6ce=C?ng~-NJd6mdE*miaZpExcGG}5WmdGzp4IV07F
zn+f5u0YDodp`@&AekA>kDTdV*<@t*jh@*Mt>bsXT_Y7XqHyz3)gZU6W{CbW1d7JOy
zHg}Ksyyw}>Wz5sNou&50!R*btHw}eYOAKU}jjRvz<cs8d18X6?e6=>#Xd`P&pXH=Q
zplvf(G}A8neJEA;J^FPwIk!GUTUY&@Oi9AO3Z>Gg?hM?I+=<-}v-#!^jS85g3QT1A
zUqwcQ)V;NQ^HmH=vmmu=xu8d0ug(0-Etu#cY5-9(i5VM|ju7{!O1>m^YL+oFK%ei{
z9GQ_7&o@jIW8$$4Yb}>4cYTCYH0IR>rv(0_0`RA8a+w(!n^)d0Gg%JX9Pf-k0jhg)
zwF(Ec7UBYqKrL&yz+A%2KAHzZOX|DG9Ij&gCM&G-uikqI1X=dqo*2bF*jJXeE3WD|
zS>O_3WT&En-EzA|c6GM(*z4qrYz!;=6X`4cf%JR-A0qwzoUPE$pJo56g8CUkoayY7
z9_`{-3K3Y&-rudUmo~??tiJv)1k}v_;bF+o(8yI)uDhuqFxsXYXjNC}URBp6gwvIK
zt*gBg3%l}&Kt}Y<%L_{Qjabra+biWZ>DH`2*H%#iVaeDowX!fef<El2w1wu4>L^?)
zDoR9vQPtJgYXOlydGaolTkXW(zjK^#xDyl`9wh@8%IoaVorBv9OGdUA5xI<j=kSe<
zr9R!|`hc=Ct#w^34YJhkJG#ErMxr*VA3^b6?z`rzR=@zMGBZD$P6`DY9ga0$8+m;T
zE7o;6s{rILz}`d99rgDz8Hrdw%Qb(Jlpi3mKzxEG{rp>(*JKjO4IhkOu>rrQ9~<nc
zyc5wS7aKkQ7Pfe@BI9I74+`;leXvGRf`DwQ4QdJMr`50Xx3&#hX1c*A(U1U)KLWrF
z<c~r<8h*!gcaDN|Vg#jN467KA$#e6?Wzrq-cT66|aD{2!bi~^kMiB7vBcsXuB5c^%
zY>C~hQvwgpQ?D;equWb^jRJ|BEcbJ*y#0imhZy&=vGMVJfke34_djJ>U%34rO^{Fw
zARG%?@ooeL0CR6gYyB1TD7|ov^VSYghqax>!^Y~HnHmgFpP;7ZQi>y8&5OfG;~}>0
z-k9N1AJm!IEzQoZBcM&E<jaA>004f!qCH9hAwivCXC1xx3c1}4CCe9o3%b<H0*ia;
zUB#DMdyG1lS2-)1VLr*O0mN?C&`U>DloVe{PP-S)7kXELHE2eV-Q~%H2ImH{H3#!0
zE(g;E3t(q&8}31HRo_w9G!tjbmbmkxCU(isg}-&K#5(6?wu7{|s<|lr`iHv94=b8!
zEM`InXiidU>bJQ%zhvU1QnV3Q1lMU!d5N!fKYfz1IJ6;oy(gIBBu52?GLoE;Kt?y2
zpR|ph3GtlrtZEGX>8TBmO9*dz8<qDP(#|TaKbWFU2to+I$y1qXof}mhpD3;rHl6Mf
z>@>>D*;0oUPc}xfww7T&GeaOCFiv2%6tbJ&a))!hvWccr67)%)=Y7m;B?j^<`l&X5
z2ime&e*^7mX#j&qMxYv;?b_<09kWdZ>-K!-OYG-gJ$%eXu?Bjg&%CV-&w#iovjPU&
zS75dG&Tvn>Z9tWg!KmR=Q6b3Sbx5%+TCypDi^FLYu$bto3wX4!<G30pc0uCVvT3~H
zPkP@uGlhu$Kmpdvc+93_;g#!Roz@F^my%*xj~SQ~o?^3pgp*Ony?dZtADBkrim1cx
zdc+yrkPv<=`Ba;4)~9_hti{cUD$_cCoL<x1fVK%I^V2U2td|}L^dLPXs;KK{eEgc5
z&g@*}rsM*ZPu4R3p|m^CdDLS<d~B2n{4q@f<8-~sE{z={(;_+}EnUy{VA!6UHf$uM
zL$_zXLPB8h*ryFLfvI4S@LD~VTOhWxxER{q{dDzK8ll2y>~ovo0_(0@i{ISXQBF{n
zIDuB{`L~`+3IIw>Km%DI7+lfg=zOvrXirria!utztk)FRDJ0zWGJ#HB1LV)YR#f!9
z#10`~k@74jTW#N&wvS|$Mx)9X1T!)u%OFpt%-Y|YpyxBV1e6ml$<1UMXhHVQiR<F%
zRMALvWRbY_YfVb-=41rFpXo+i>iD(Bvao^P9kk2C<Ls8t#lpnoYrtclz~!z~7@zx&
zl$RIXxN$mVTW8NB{Sb3QbVr%mR<c$~wONu7p|59P+%TT3sra8T7qr?w-2=05KYsd@
zRt`O19fIB85b117Dw_EY2eBRprw-F&VYkSJdbH{M#(!W5!i0YwKe)^Q>fj*X5gZi0
zw>O9HJTPO5_d}A1N^Q$AvIF*fy=h+f_|8U9#YP4`f0l5w#!V@fkYzdkyGnd{cYIPH
z_7N-TLjoPvaj<olkFWq4^An`8JcUTq%8_a`+FzG%G@oB?kiW(<nqIAoC5OnC&eOML
zm$z!}pSHI=Jmz3_E-X<!-dTi->=1lu0oNrE@~0QzdPS0PJH!oGiyPl*d_(+8IF97-
z5=RP2K|$l&o>M7*A3E!NmhO7Bwi>X2K{cp3u#LKEqpqGbS-fc9-W2)Z0FBi$ko}Hg
zm;tob^8fgXRpT8J94x}!5a(W>Wd%+zkI8oLC!<As9sss}<*p~&;WuPJXTP<sBPJtD
z(|xI+(FQe+Fi0_M>;jZh)oKU4Q#-r;Gd}+)dJ+4cs(sbW8uM@UcmhKTBXaLZ*nx>`
z9S^s;ItgQ#!H4v=E}hX>Mi~BK5C`gGcF$D}w~&Cn#t=4`rYu9e{}_?==P@M9_**GK
zio>AM<ty&qgZ&fU%uBt($c=N;MKq&YS<NCWUsh4Xjn`INBkc~^#zxxP#6mbb&6&kj
z@f=usvu^7!#ib*^MbzOQ`b%|~M{!`Jz*rc}3{;O&VLfXhR<Tc$iRQJi&!f<|=n9ko
zHmcB7jr`6pV_W;mcXKhEj*z3y&t}-}giel`ljWb8@c{)Mm%}OTx%f0I{ZNr4!|E+i
zrf4>vLJn%Qdio@TFvS*JE`9Iq<>gt-xqf_|<^`=c;^J+Egap#LpS)aR=D^gN&yIg8
z$=@oBsX+P#ew(nwN81zb|HIl_hE=t#f1rR!H_}K7(kb1oq;z+;pmc+DOSec#ceCj3
z?r!N`G<UN1KIiQJIqrME+~-*zc$Q0?jy2~P@B990k;&wONnOQD)>sek)mQZoLb}!i
zMmmwgn{EVgCNY!@pR`n%R#ReA=@!H!5&waHAs6Va6Y;+6Hdg1~ZC?ELms|#7R(ihI
z!NGk1>sZ;oevjp`WuAkQ5*y&k1NaD)Fv<UI>ky-xg;J$GwNw=p0FDF8>S|QN#Eo5X
z@c{Q+KHkT!Y{BdxrZU=V5<cdU-mzn{H*cU9Y9C+>4Gpz(O?3Y(@df=c;ZRTlQZ#jJ
zp2lsMe$&Y%IMQ5Y{f%EPSdRz|1LOPFubL?ZARAYmZ6IP;%ylcOYHO9%*43QdexIKP
z>er9<_z5%f$=lTx6_ZNZYkL<%;hDN3pQAVc7@J|LaBYYKh6zn;t(nUv=yx!c*)#L6
z5m^&xs*s`9Up*eEClkx&W%3mMzRRKs^4|Vhh-LJ75#}G*kk5ZF_8Isy-sn~T{V#cb
zSIG>x$!RZUI);AVE<Cq~R0P0h2D+mw|JE!1*N;C(fsRjgw=^*2?@RZ$RRn(g$PRqQ
z((d0l@&8+^W?&i-9!`7Zh5(P;;o~RqoY75o{^re__1=}9Pq%~hWY$IhsSyA5!2WSf
zt(5>`T^3;b4*)P0K<_J$F~M>^od5i>gDx`9VrS_51mrH9*EO!Jp6IyiB%1wZ?;SvD
z1yn%>+XpX$f`jSHM3ufE<;rCE4Gs=MUGAmOs+Mj557>_Z+J~_U8PkKag+d#J<(8*Y
z(=b9d9hf-VrG~=E(DpemsIk*6)pCy>hEyJ>X2FGyW$2eHo$D03*tkT%*exUe^$B=v
zL()T3G`0w{?dYtbLXkD<L<GV{fJ3(#p(rNJFLo&becl?&H!YX!+)>NNWck0={jWvf
zb%P2RS(b3UklR$rqvTKK#+Fs4AwST8j(0D|?vYLHIxqI{PF=itD~AgSpuH}J`udN%
zq5PXjwl38wP*XW+!vAURqVDh{d1`oXjSDN*YTX3HBi#!pCw4YBS2xtpPZjPQ6W^H=
zIv!v3Ja>5j`Du1xf%-h?HeYdB1kfSHayzVzu4O%=Jkn{rLfV(T$Kd0Yp2r7RX6rps
z;}VOh)YIvd7v=W@rK1Hos7OdiCx`RI&jax)uTz&CU3Huz#^vx$kgDF^VF+xG4R#{G
zF_=PBb{3-0b0`Yn0Y#l3qc#dM{?j^0J>O#2?AqD|)YU%@02$zZo0Gj?+fxnTywJKl
z3<LORNv`y$1HpvYX^RvIMaQdQeamTaTLL`4V9SdMPMP2LJ44v^Bq#1Jq2Ic?UZ0$p
zh~{pm!=)3Hy}rG@HQU|{IhD~-=(eP}J_fpTcAK{9{kD@+8ydNNaUeI~C^Ztms9#f4
z=c`@a&|DL9LQ6@}BH@q1mZBapdi?)Foo#X;01yEEz902W>@32yC23_B=W%Bj)+0pP
z<rbG3gf~189JWhcXN)b~^9}+(fL?odrL>lpqG@}97!AO7XE;4>>Gq}yL%AyR2JXCu
zwOi$$763Fa-8;+BSlY!a6{9LVBDia3K$UcL_QSL9(nW8k{UM+PK_XyAfe-ErYRm`%
zrVf4elpqcidQE4;T}{7o^K%tInNM)Z$5-aDV{?B$!LfCFSB`(fOK9RGF&^&~0_`XB
ze;B&2_U~VwE<wLsYCSW~_#uhab1y^p`;MO1|M@$;85iaLFJ3O<#VhJJoyv{5h~mhv
z;Rpx{p$@k^HVljdQQdXAOI2mb3O+Uj&cgPcZQ4FHEI-GK-%3HkH4ww2y1fNVz9Hew
z^Ao+?VFO&NeG02z6v+%qF4_PGi|9NII<EU&8kpI0@jXB<(!WCyaBez|sNSF6IH(t-
z(_$h3x09D$S2D`y$;tp(;)H8!=uGbh@ACZv0x~s}P3yPooW#jUnc@9baQ#sQ5~1xv
zrpL#Bw0iz;4@knz&5`r9vNGm?R(2tT3sC!SJ*)~nj25bLG%*{!TXu1y!soDoBiLV5
z99_RCYjk@}_q0xnxB1Eg7%IlHiIvp?`R<AQ*58nDO^r5l^LvMf+p17aJNo-E3RM}p
ziZz{>+=j{U4zPUIx<a=}m`<QX%iMl_yRqkog>}1O;GY17F6Fm{wrhJDFG{aG#bCzb
z#HwF)x7<N8Xf-KiJ9L(DFmDd|i0z%L;x^81x6prN|56qUrpbQwbHwZOoh%&C@d;(0
zu8RE*Mxr{oc<%SoA4e2&Gf4gqx+=USiDK^wv`hf+60_PuMdBoUVYcQovEw1nS09hY
zgkQH5GA0&gZ~PkBbGP5i3{#DR{^IuTbNnA}?{;qWPkrmi`I@-UuqhRQ9)gn0KZ6TU
zzs!!7Ua_-JbK0$k9W>88q1|5nikL1=9&i(A@c>+w6M<VQMQ$=Qrgr)X#=KD3!B^_C
zNpWt^E=wHACod1y6?_ojg2*2;)z?=qBpu@}qy-@AKljB7;2av@>}a^2n#hU+odLc@
z{{-k}L9~^FhDI`1hKZF`Br5<JK+1<SYd@{6W8uN!2$?cJ=g^joJVi-!kZz;<*eYUf
zK<($hb<WW=y}w;Bx&M4bhV5}1+|V!!HdkB`)6j5@=HDAp$<9Qg)ghilwX*~3TN)|`
zRNB-0c1r2<mI65Nuw4=?hFNSsxw^vq#qMRgFMb5lqINXh2IR@!r$)v4`T-mU!3@>@
z%Zz)=x!h?B)%``x{2zXRN)v;X$m~#a9_EE#Q$}cJG<q0PxKRUKbc-sq#M0iRO77Xo
zCyC7#bKKbeK)PpgZ$wpjbu=|@XLz;4QQvgc#k<6mt#m6{8JV~|M`C+CE@{BCh1JyE
zdyBTYyW!X?0FW&JTMLxMObPtyD2H7z=GZz#$xiaSZ$kPmitWVf7Zsd#biOM&$lDrf
z8f0FrnxL=w`S}fMHpgi^SQ*^ei`d(p|L2tdcV)3f7KO7!oA4{+@q>(X*qZvt>z!fU
z>1%yDAhH3fTb%|g>?}ukboPc>1v_CtEp3aFmPa%1b?|+AGDCShD2+{6<d}L0V4Jn}
zQFDwG!I|V{Z|0Dry)6(c2xw1Wn*3reIiS@?3eLU)xvjCl6$4{tM@B;Bg4oCG%G_$v
zG`QIi)syg)YpcG5>+OZ()43n@pRU1eUu>Hm@huvrN7)I@e~HOiSRQH#cf{rs4@~p|
zhP8Zq^kIa|*`FMemUSD6z5-p33r*vvy$BZVpqSrRVZ7LoLt~(xiZ5N-o9|oAlZb>j
zLqM(%FtX|VfdR<8TLGo8E6-GBH0v2(oAxI?h*UyaWgvp~L&d+FwLe(ClK3A(uCVEo
z4Z+I~aFIcs^{t4Uc4uMI)T9BfE-vfWr;0(5azOqsq@<4SWz~9>!=VP7k*2sfOy`G<
zZzUSlTE-y(E9{Su%;K92z_%^3KTR)%uVK~L8|k)rY>3uojDAuq-|-TAyPhj-ziukt
zoZj=%m>giv0U&&M<rDP!Ra#?zs*R1qCch}i%xlu}FqskklaW*O%!$5jET@C4I5vy$
zdS-~Mu&hRaf(q*3UqoPQm06FVyZf1BTd&SpctyJ%oA-|v@xSkK(-j~AD(6WT0JOd)
zV1J<2>@-)Ci=5w`q6cRT1_t<VfQvo*sess7AQR$!y_c5%FNvB}N8zxF#qY0I+W*KX
zM}^!R)4jY|S!8gnkCS{NswOa$8dWER2cgITt~nM<BIXlny&P%1!L+jb+X5c<!-;E&
zyv8uDS44DyPW$udfL&3-R{W61NzZiJ?qm)yzO(34eJuYmQI=V1c!N_29Ms%NUQT}@
zgt}w8lS6k#FqATnXqvST6f;S804iKN@i_W!F8`}QMMVXZSDUFMcgXD}AJhIuzI|+Y
zG~hR$6bMkOGcCb0MroYrAgf<_{Y3^3fQYz1@F2KfEMr(WFkznh@CS*4eC!oQJ_Qnz
z<U*rf%Z1b$++l-oe$##>1a{hf$4#Do#ZiRQa&yORakPUCx>W2VVDVdFW&Pkx9P!i2
z`yZxCELeZ?eOa_C4k$w-!UO&5lic+Z7$9rL4@myq()q*nZncPN3JYTl4od4=$E7r~
zd);}})5#8oxYs0)BLvk*KJf>Y7KL?=aBy?OprBldHRlCtiwsf|rBXIKX=)Ck%7r!(
zGs>az%r5M|TJ)IZ<2$kgNR!|HgV0^pCG5EVxi|Rq(4Y|#B5`nVq|FQt(p;B%cRq;(
zshY$i)OM_|ZXFe!rxN~MBjIy~0a%?u%fVQVv9U4xm>Xk;7gr3)e@^L!e9G)!_XTxT
z^U+0fk{;|{@4EP&mojd@YTH^bk>K;uT3p1+q-UqZ1}J)+K?>PfKjH4Sh<@K?Ndi*&
zIwSI{@2y_4tz9|X+ny{B0^s@^pWofSt(A1Gu)TZ(D+~ez|Jd01cmaa-ZMokMS)Wn3
zR={Qupc}U)3`V~H?aBPdDzxc6!u<Y{pWnTQ1%i7XQQiCQgMPpBKEDe@`<xK~oQ^+<
zzd1RuQHim1x*9xX|9owNFVUHbNbY`qTsRSMew9*t81FVdGb8aIA)?VzS`<@}#<>9C
z<<fsQO`ozB4hf=}G+q6V`_8|2|9@TC=Cd(LOLvR$Uli9*1qyijV6w8!&}vS{b-Hxh
zLvlF;uku^icNZ6}-kzns=wsz}_$K;T|GdT_<j-y7ar;zGvI1@Yv*{_3y9A6MqgF$}
z;2>QS^G_TkWMooV6iu~6+6VQ2XhxsAUi3d!skrm)oArx1#5(LRF91@Z^JhKVIaU@L
znCa>G>-9onyE|Db-o0t@NCw7C$6|a969cw?zO=WDz&&DqgYwr5ok1I3{IWn6$U+vn
zl9rVfa(5>qJUBdU%N~1H|3$V~O|u{t{_bY`a~YM8fbPE99hG6~**0)1lwW+$4|cX`
zO77|%2S?0t>E*AGWVV7ViCUDPU{GY;9sK|2#p!*5U-9`jZwPsAVt81knE-FgWEN;y
zzJZgHk|+i{O@3R<{BgI+$pVNE@|6UXEIB~N`@d?I{&Yan((BaXA#t)Qgny6v+Aq8s
ztAJBwoC)(EMkRktIglXv1!X(HpH9yltY$Crtj1<$0`nxSFZQm!HPte4bnKU2wlfmc
z>W?&c09Z+&&qIS{qQCOLZm<7sx@jW*pj3xCiKB>XxN-wot!sL=h%a9FL4oG0ECN*M
z(?x_0FaY)}Le*)&@8&&!{7ONwSHRR~pw{4DvI9svgG3*_VqU9%yq{<iAwI*XmN9-^
z_?suue|`ER5zsLu1k&vM-uU_X(;wS_r@KT?7p_+1A2*2ayufD|P?d*2{PRbA;Q_zv
zwq`V&-x3P`{7<?7`T#AWg4Acts~|PBy}kW+g?!1e813I}KCM}Z0DZrUNh(L!O3U3J
zb<${Ob9M00*@_1z;%D|3`ixwwLO*~_e?mYG)D+rA>xr;^oS(oJ(YL0>WISt-Q8DL}
zo<(J4pHjKpj-s!;c4Xm7bP#DS360B5@^RddUIQe{NJJb)fk{a+I9|K)K(pln@@Dn(
z2a%yRq2GPqKx&wXHtapl?Hw_1$k2l0Kx9E_X(UX#1GB{}1TH?V-u@NeY~|B28Pd6_
zOaLfNCi?cQWEXUcONPmMk{XJ<_?mvz%vfPrYW<G*F>p9d$G42yT{|4PrvXu7v{@X~
zE~9Zg0Zg7Q!79>cM@VlGEsGy$ghjRwIlrRb5aG>`XWE)0<sApM-@gQhl(D5<ecBsT
zKbS2i*l*U(oT$4`10O6!0t&iB4pZ?*i{h>Eq8mU&YBpWPoXlqZ!y!Fnd~|CoLaot;
z4*;0dcIdU6?U5mSWY<c8*>C+fzu}GltA+X367YsS-{6yrdy}0KiaqW5lEz<`LR-Hv
zPOr}fS2{OWqv{-8`?{;5E;LLKbJ#3-lKHIeW`7~9CkmxK=WgrkRs!YNd$c(0qg>q(
zcUR>fn``AIDaz1Q{3<M$(aiae#QM7dtY22Hm2bHOmeLA8${4Y&NaqQ${QmmeQC7C`
ztJCzkTR;jxLR)C1NJuE)i7+gyJX-W?!%)iO1OgsD*nX+KFl6GGZ1qs1<0UZMd70ek
zaQKyCKxO@G%kro0N|vDJ2ad5Z=1*UW27z+;<L`7V-=$xM5FOG@{K^>a)6y=;1n@`~
z47J$T2iA6c*Ae$j0Gs{Or?MDE9v;Am$sOx({+-tWaaB)$)@~Iq_^W;CRL|J@gdeBF
zUGt)Zf(CZ?qdm%0?ve0=x?8#ZQ#ceJa!o2I@U+=St%3*6hV`m<ratPcf=7VYaGC@k
zD#z?RHs8yKtMm+}<rSPz*#jD;89>Ngwi!#@eei%+daM<?m3JkaU5hpY=(r6Rn{|y`
zY+4<W&hH=#hYuN<bS8%KC!PfFSswsPyPTUqVy`w}^rLVz(C|G(s?D#(PoHPcWmhwi
zgq#Xtt`E-{?URW5-o3vRi+?vzOn=;yq`ALn(KY_a?A1a|JlJ`}N5Qj6Ob!*+t~dP_
z@m$rC-qgfc|1nQ$>?lW-$!Xa%D0JZAAqWzOQ9HVspPpy6c+JpmYtO-$D4IxkQYMiT
znSjGaeou__$g@e>i=;bvgvp~@i;y?g>6^|%G69Emm$y*Ib7u@F-NfTpG89fa%Xi7g
zV+gt3t6G!iZGer`=qZK6mR1`e=7dLQt<XoUZw@AXPUN!m8Gq|V%Ek5a0TxNb#Kh#$
zLcOM{Dk?8=Bps1%Ttz`l9d=AgBl7THH}K#0Y{5SiN>0zxZV%W9gUeb0Qf^9=!+B?%
zUoO8S(Z(lOM+>?PdAqNV8B~yMd~+TM`WuM@*t-Jc`A-Ux-3lB}ODy5)&_js>**Z3d
zj}ogdS?){4sqb1cl6`a|R>WGvaorzWF^dRi;cj1|^3ix8;@GUf3k@Z+A*c@AQS)n$
zj#U$_PbeZ*_54mGpm2o;uo7~eTj&NvK=XPg14p>K^7fxVnW`R(buNf+<<jB|yF}_d
z@B46&LHMuK8c$?2G#ZdRLm<r7R9A08{Tp%WMi54j6A7m51=~m7>gk!Hh?o)>Ee#-M
z=jHMXemtQU72R~fNfhlE`aHts3-={tB7YsB*$y)h1$MQbvVNsBfK)P$vz`VjmDrsV
zamf|Q8*bXkrQUB`M@uNx42v3}S*sb2?7PeLd+!4V-}VmiFbQDJv3l2HJC<FJ!=Ds`
zqvz;Y;`^*1cyM(<cVuj8#UNm}@`aQ1I-g>h{3-wX?jDsoL+Z<9P44XZIK}xIz)pDq
zdl9pRnk!Am<RooXR3#%RN%OJvup3A(1L%&crP^+B3=5Bo@J?WEe8p6%v@cXaBUG{j
z`}V;rdjRioRlYWYp<_1TcZVx)1;m7?8L70SY+K)i4;%=GR1V&<f8S;Ggt>021l|(J
ziK>j%tuFL?$)Z%BXKATi<DC@kQ!yLwb)@gSki4t3B0p`-{TikvG<tV8$*uJ0dWvAA
zZBC>10t0;HKR}Y<8gYMo<QNeo-G>;qZChwy6VC7O*>C$V4FDki&-_aTF!L|vIa9GQ
zFz))|m4jGweDchZu{)c@o2#`>iPz`}dWNWqG_$zmY^wK^Ltm$)QH`rXtn)cOqSPID
z5U-I>i%<|zf{(W}vbZVb@DTw$zk_n{u?{k?e3m%d^B|hP^eXDDuV(F8v^jJL!94&f
zr~xXExg0>zo_Mj$8J>?4l41xj510U+mDHiGpx&z3#nC0g6)`VaptH-A#CtPb-u)^6
z<A5PJga*<V`R!#YGOEC2pOlLtr}aYOg{<DHcQeaQ>9y9=or|H5qg|G{40;_FBVb8`
z*Xoe3Q`}p}UaScW*s;^obL9F)D<wF9OtY8Ec&vm#@*_)EAL>f+x6h%Nb9i`ob#~|M
z!otF3M~xXq9)Kak>hRLX#bys!)N%Wk^JA}TJb?Iqb{^_@xusT*G5n}_8`G9jYt<8?
zywW;6jIHb0{GJba<#*+5t0DSopC0|-zYE!bUg`#yLS3J9GBx+hTbU|L%`@t0s22k_
z;zqh~k#Zt0OlggC#HXx3G4gZ#%qc0-ozmD5EW_2TE?^}i&zhQuy<M7`*ZF1n2MMAH
zqG0^HVWwN{@Y$w0pmE`Sp!V$`d#|-fG2T2st7hpQtfy<2@Yv#W-ur<-pQD_-6Mii<
z772GYk-8%_EzO9jN_k-Xi9wWMzPa?Ov*xgoL^k~KW=HnoU`#nlQIixvJ%QL9vyUwd
zdku|3(3B4K_#74_FWL;k(u(OZFh0vsN_>@QUmn&-*FolV#K;>-75P&juXAv*K3UC)
zrCk_bcwlN^K<2l218c6y>P2k5)g9iHZJjn>UFATn@YH@@47gR2K2_*F`E=L|kiDlb
zx&8_b#3_&h0Vr4K#-|t=ij%=-4|UFS9PCGrEgp#Ju8|=T(NFy$!Ug~00?52lSCbM8
zOwefsWMnya5iRz_3i&y-zwIvslMr7KKhT_Sr8mR>XE?`DcH_Nax+%bByGX@Rru6+3
zemO`l&o2(%rfc(MvG0#>AD0-w7salYSJ<fFshI-x7f-vNFcd&KYk{`;`(2IPB4R3z
zj*oj71M6SSfcaFJ!@lhG;d12VN<u258Z@2mFRqUpi)7V8mANwSYJw%BF@&`W5?{?m
zxIl7I|LSeRMC>SVxrtF!P_Vl>Q&wA0Ys)HWoUTXUXj;6XpnE#Aw7T^uM3RpG(yktc
zljodayC4bE-UYu_H2CG>;0B?=$xS^krq3TtCVL;U4@mh%TB>eDAn<~4-liTe)+0uD
zlasSz0uT*Wdh@IsAPmGqo0+8MCBw)h)&Hpjq7fYhy-VQiqDvJm2s$}=?{cQWceHeB
zJFp(z5-F4oPP`IY7D4ZN1Sm2v(N4~H!%G0%@5`%PLR9F9lNYGl>!hHjU3#d!IgkBz
zuA}45a3hx<7d-slT3h{Z#zOy@a`bC?zx88_`d=-=qg(RFrH9pMOtYhhRQKN0hLRsm
zElQ;<o&uNwQFTg$Em(nms)nP}Lz&VwZ)Ht&K-gi|&O^UQh)mD{okAi$e%sTLa<;KC
z8OM#-FO$8QS{#)U9a=f}=~7+$TZmJLR)DL*)(lMJ>t@A}59sx#r;)pD;(QJW-xLX;
zct{y0Ru2z6xPon-CHx__)3J|`_6G6*DpBQCjtqq9Apj9`KAg&$$x>l%=i!jE%~Lp^
z`IAUrlmjaE+z6^6XBiKT>NBCm2T`k=4Y{CI7gtyAtAi!Rf#lnrQnyTNORF10SOA?^
zPtXm?4eDJ{Rje2CbA<!s2<uf&j*e}*?LIFgvWtNyAvwUJ7_-gpG~uPs4&$>WP1V&z
zwGi~<6PFXZ41PlDLjB3&I%#Ylb)+YE^GQ?FZ<Wwp@Vtwsqw6N_F!KyL%@N2ckFgn|
zsY(|YKf`sF&V1i<*angSh!A6yxeBSk;h-un)5(IO*+p>6;tE8@-tI)zwR>I814*^z
zjA$c{#>U8DBh%(k6J`xTNqTEWn@hbS?BTVFY<=!|lvm_q!N}8gNp@Z;>@etmJqRSL
zb0S{rcA845VsoCVj|-A#1wPI3FdX@nd0KwzaA?r#zS&s=YHNjf;CKWWh>k)t`*Ajm
z8?9|wyVE(9B_dnYm+|yXq&lcXucYCBm{+tv-rNPbx1R3|x8{Y$>z{sGyzgJ{v|Xqv
zHmc?NjAPiN>lRB&Hab5#fVont=`Zx+ZoR#00QbI|s>*B`X{vy$ZI*K;ua0dhCRmBM
zP{k`0CCzmJ;%Pg)-o;()u46s~wi|FqQO;kdB2LWHk$PZ|g_KKU5%SPnU21P9v}}GP
z3<z*pDR1atXaNC8E0n`Lyn~1NGCdugQAlKVwvig2PwGa_9QobfE55(D=qCs8yIY$<
zbd_>DSg#3C{|u4ZzZjX5IyV<v9_{Qj0_^Q*T$H6)OUN$a<)i^D1hQx-1g3(>I3s~U
zx9ct@&v0gVhz0J3>NDS-T6qHC@v1))5q{QY7|E@h-@UU*LQ94o5LXP*;TyQ$qFqb$
ztmM-5m=Q`?tT9;1@Zd1GyVAb4_Or<gk*eMa+<havEe_-+1U3Zo4m4<yfy+77pM>vJ
zPj*yv(}=C|%!`4NHxAWxq4|&_oSNWWIJyHF=kiuub0VuHw~l*xag7c44A{dO?%DCj
zy(weDrKneg-|AXzvB?3)aG5CJSrg!bg7U{ez^CF*s!K}BFs6wKmb4wkW35ILOQllX
zYiw9XC)2c@O^Ck_VPX>m_4G)H9)pZr4hwt-|MWu0xy!r7G8z!8S-U@eF%t5Q*Feng
z_Oi@vhB%UQAPZIZ;gb8l+L9Phvz%T7Ufv4;zW%t{o*}&X^EHo2ovhC)Kn=XVIJX6q
zLbUv8Pj+k68MB~X96H&FJ^SGMMzWl*jhe3s`7t0)TR8!(N`rJ}c`2N9qf#lQq5<5-
zxDLQ?_8ZcC{Hlm00fgyPRCP#BF+SyQDIoXG^eqk|wcL85+OZ`5))w4Z3yK%-zAn37
zHVF}siHUP^tF!~fk9X$U#2pxajJbRkv_O2hH|6iddWc#^`?=LVkqJ13VNr;HZN(Yj
zkA`%I6U5)-duZ2yMxM~V#l(!2XcO>C@1bZ<8~jNpa&~>`%yRwf;i&HOe^%0G95E=S
z4Vb_zhw}ZcPDvL6=4=^ljB&(&a{>Gw<P8UdBkin_jY#{uamZhj&Q<kis|M<OY(^M=
z0sqGBe}F!y1byBD!jF@f$({M%^+A6=6+|&WYaa=pJn;O$j4G4R(n`&c9{l$7sCxEN
z@TdG^7{jYX6W2`yXd~ZCOHR*TRVj7n7_}Z7ym>?kaiP<cm6PiMT01lhd=(?mK`P+^
z$OEr0>6h4idQM2HG?qP)5x*4ihYizU0AB*Ccea{*S|E8YJT#%?r){Xm)7`FJ=TanN
zjhvW;R<$d=JIDRwsHVoll*V<{fj4^AipMS&=id_k{(8KDW9}6;6P;F@TPtAqV6|MM
zsQ{RMX8D+EhvBnB1i-*l*z_=XT@!N$TwEXlCa8LXD@SIttsD72c<>2Bk7%JrLD87_
zO0`0oV9BlKr$fMR-+rtA({nwmfmcB1?saNASymGm2vUr8w8mPnN$q&3QbMvG)zC~p
zP$aIkVqA|uh`uX7n8Q_8LGn(|m-nC3RkwLVbxjG7g~CPdoE}?1=iZS&=G(7pNl8gx
z3NvPcmxZEqUW&G!p?y?(^$`tA6k14-`iHOg7f3O|k3vxlBp~oI&sQB05)f#mJ|$_;
z#*rf>0Nx!8GCo@LeEMu!>G^qEt8u7gp$t#8R7c{*-uQwANJkT|E{OYBY+=kNL*@sA
z+LL%3K&}~Hfc?w-GF!beVE0kTw#sq=Aw4}k7~jNM6xuWG9Jcwv1P<`-kNVj_Ck^#R
z@HejrxKWl_n6&jS1Vg=+^h72Ts@uz>fDM4#xpVZQVAIb#P_5dr62tp#7?H1m7~&eZ
zC4Rw-!uoA7uPf%#9!}e02^-UQu|6f@qNXE$!*04Sd)LWB&5PPgOa(`@RO=}dCe5Hu
zL{yuNNl;ZwrcUoss3hEQO99T=(>Xd3BTrahrQ>XhN`qXfS|;6N;*->mopQ?=9jz8m
z*0D>4Lg6o8-Z5x5L%CqKs?>QtzzB<MXjUfBs6!b`CbX|e9fq#e%*RxH|4tI8ocm>O
zCE=>O^$P|G<o~>U@?s#m^ay6EKSBy@jwDE^LrL+vvFoOCIjP4rdF-Tf$5X2#m6ViF
z$rmv}y&zt2c&ndv^YqUAS0;h;QHo3=XaiyU@JjU*b(?6ir)v9}J}&-pW6Rm4UskKh
z@)tr@*Y)A`=VRrjcXmA4(xo?nmkkkQswG-o53oKzKQ>!68Du$@3eT`rGP{E%7oA`2
zAgrEsxH&sr0`?isn9EvRn0(U@0V1^z$`5=Tj6VkU)MuUcS?-CKRPDH02n@KEozozr
zRIghI9<tIeXV#5(C!F*ObUId*dsgSZzu_&w7M^^4j!XRTx<?y^^<rOs_rgSVvB5!;
zI3+8nZXxQ-z@L`%WQ_dF;Uja6l}u_co$n6d4}CJX<7c;fBHySTG7vj#+k$F$tcRp=
z3y?_MM7u{p62xKm+pvbry)S&qH}bv<ZQxAR$)#~;?J%m<iPocWxgNX$(992A0uNSE
z>5S2QZs5WT)rA&+uNmvA-k95VgY)=9>|YVGsp_zi#IS2#rA|VkU#(||+7EWiG1(jQ
z<v|Enhm}p;?1&l^;^N8L6LocoE23rn+tlz;5Wji7NrG4sofX14VM4n@A?*59xns9;
z<niTbR5tF_DTiDM;kEhn@lUmqSL`-({@s_Bq#{L#@H|5~Nt@j{pMUu3njqcYao$&$
z2#*AatwoQ~aWBCki3Mg{eV54kab0dG7N%u~as1$lM!;W~7x}bXE$H5`N_G2=HlkFA
zCeUzZqf-+U6&@7S2KXbMoSsG`+?mYHJEP%4qx*|wt&7%{?Y{piD!#f2O4(H`ruO8i
zM{LPh4DYW;_%4hhfK)Pt|2guw)2~d=U8_3Sf}>EPy>v6w!M=xMS-Jg7Fh<wO5?Ek;
z2M-gYDL`Q47Wwn`Ba!XBa-mXt9dUDTf{ipBxFs^I>oX}gC!y0VqxiNg+o|&$sUf;n
z!$D-_4ukL_G$&@~l6VXyGPB;QDljMxNDe$H*37G6odTAL4^Ze}BR*+_^ae2jM=ZV=
z0#1dd>U3RWW8>L5K<m~ArK$}Bd1)w~o-WGs06Xb9$Mc@a=9`W<ncEdn>$ov3^X9<F
z>F%jv*u4pzMvYlPf0c74JV5sFd3+J@Lw!QrY`%(gQHx&N?7q<x6Y!EOgx*JA2@{&2
zMAm0XQhI0vA5l9-67f~+PK<p}nDNPC4|lmazteAP@9KV&x8CS<tPGYc(aJw==*ovI
zNBhn9AJwWT;tizTOWo|+p<NyDgcZ)%($KD@a#a+5BjcYcQhzz1avw^-VJlKZGZ4#Q
zlNVQ&aImq4aM`yRkh+W~|1K|qzn4C5h@cPITpNbShGBQ1>5Wc$6Cww30GS*%Drk{l
z1gq6_Nb2Xgg}=w;7m4VUTAMb;40XCH2G!QLwDu+;j2M<%%hXT2G&?jwjhRA{_i-1}
zC3y0a9B)|~-ALZh2zOPV!N0CF9tZ(43A1)29#(e}VEF``aj<A(rGDbiH&0?*?swy8
z@Ue82m(RSv=s-&h+3EDN+h3h(qT@}86<@vQ^R6Qf!g{x|dyRjz;svonr+&bO$@q{~
z%WZJH{KC0*Kd{c}n8-6j0Fi;g#OIyP+AMVW=xg3DZ>Eb^e8rLXS3@5`@{KCt&|Sb0
zmt+4DFqy_5N?{WZ<XG<d87&f*^C>4}D~j1rd`cu!_~oZN*?Spy<5XmV$*G6c5;gs+
z0s1%=(<^ymR8-W>-sq)V-CtLwpfG&4f*(r1FcSGcqm<}?0-#==74q-%J`q+JUy3EM
z4Bs6&R-phF5GIwt0Jyv>RX+_Btqj^i#Zm>Na@p(k3@_0<%wH0ymD{tS5c4B2GBSQS
zI4O`!@Uq|R%`IB%vY$^16a&0%+jm|x`=)5ZguQ0PST9ZWfqw7(o0q~jh$$GJcZk<p
z%AS5b9(NSJBEn^6eHO}RlS${2a72^GBJXtyw~?9c<_Rwmn$mK|WzLFQnPP_$)ZyD$
zcE?@ZCueO1DlUTO%aqpXvClV$k<o|0VMun{P$hJ9Aj&h3eK04}d5w-G*4pHFNXgwq
z^met2*6cl6CW}=3;3@y|vYl^3W}Vn1g%l;UEmvUc3YhG!H9iO)B@n<0wc+C1CG|WW
zlvAcBu*30WMUC7`2U7ZJY5@F^T4*xLnw18XNj9B3t4OY^)cVvwEDeJ;ryK#Rf2}v#
z5U@v0G<eJJDMnbLkn>}xIV{+K-l~d<LAn24uuZL7zRCHNjE1K&(nUK25td%5Kut%x
z$3Sezxa#6-#MQLV^&!aVn4f5oL$i6M@kuZZ_T@`*I$o_V3SD8nRdR>NlQoghqoZX|
zq*lE>_mE2W<I>MeDvfL=K>BVzhAsEo)qYPx0h9=wkReA$c=EYl;0d`6t`J>s7b)H+
z>ozYInE2c0lz-Xc)~a`XA%=+a{(E&*TH4Y8^4k(vG8S%_5(Y}GX5u24gMIUQ=?bF?
zcaN1M_26o=PoI9CSr!Jn3{S?eP;!=i31^;LS{#tSvwT|euG|^U5<MkLWO1Op^_(A&
zw~GTWGzpxZ7rC7FE9YwwP2_dmkVL3L2zEowp;hhSo=LmCAVUhwXhg1E-)75>6Y$uk
zgCgcvm@XcM8&qJVqeI&8O!dW|qTQI`I*<EaRBt&tU(Fx#@_609MgQs1Pp!#_D_8pN
zWwoWUL`s52rYC5=!N1gjkBd>YrV1mS!)h@^&JEmoi<~lr3rvQ3RO~{l6evPBy2CYH
zlUtsYuWvOp;zQYr)W+u#BBtBIQ))j=J>j42j085hoX-~6unsMAn=RyGZITNgKMVd!
zk0r3RI)ycS;TF@lA5qtdXSsXtCF7|q(yYLX9UZT?2IATR`GD}Jyb@<LH18r6_X8CZ
znBVP)5b&Hr-tlehB-Tsia`l05sFB`kP{(sla9I6u@)WeHRN(+fO33RDuvgb+tE@Q|
z7q#T;zGsBTkE<$#lg&+fdo4KNLAIe=#MBFO@kWnu=nFK#4^;_53K$I}<Ml+ON&hta
zaVE9X>$fiidE#{eF}7~s7ED4=ij2>T(a}Qm^|<)~-;3^=Acfslsw@{Sou{TG7@WlI
zV&&_=rx~YetaW}vcD8H?J-qNDgFTLJ@8R8p>Q=-08P++a3wDyDY`0t@Ol=q*v;Mu4
z*@FQh5+N@kkm2Yk*+UUZ3tt|B#erI=LMJ#?5XXGflkdnOGGSpdk}gv}tybmCrO|Q?
z1$Y3)wdkP-V<G^$sJ3bA#!si?##1B1+IQ>9)T$*__H867Yhn^SPJB7h;RLlbjzB(0
z@Jue~Yj(*Cw?p;3;{`9csRET6S=ke<Mb-Ck$jpsD-<Lrl{<Z*#@{WO~li^P*x~Rh8
zaa>38)UA`2QKZ8fh@}asDaJ26Z-057C40Dc?XXNn(O}$n;D=HQx=^|X(<Lnskk7}7
zWe7wRMCLWpVtam6REH-hbtwwfG*s}lQ&m-Mx;xSY5+%i)n;m69_x0WjxJ}l<o{v)~
ztY90g{VeZD^;AbaoG@-rin6&UBp9n3so=H^d<Q|I(m_|ZY4mdL*PLd!I&Rg-doyl2
z#;A7|5CNWi2#8PD%AjdmZ3&))>L?|Fk|Yak@o61oyXqmMsZ`YomfrEM#g^%2wM<F0
zr}|-N^s*-nz(VpVIqQDT^FrUL=~RW|{+$Q5tH<n65~UK}X&`-bAWzHKa*1+DIWs!v
z=dGrKMfJ&IP0f1wG3dc9S{1|DpfT4|{OUo1J8O*=ts4r4C@<=HCuh~I1bTv%mQuL+
z7)m*b7?Z<~W#5Uh=@YYRb8b|oF_94E*|TF-iztdK_geuoQURIQh^mD{2UX0yCN7>g
z=jM60rw8?joGyFsy4?k|<UX^nZ<%{ulM$R#bobBAU8zU>=9qZDI!B=w5^Oh~%7V<&
z@R<=pCp~F(EuFbdrV@kaezc4U8irr|%Bq>&!xNz<&?j;=rK|ZQah5-g-s|81IhIl1
zjg{SW;gb@>J2HGH;y}`jQdlh{-;^xw;Z6UqUw?Fkmaf;%3H&1P;!->|r@_R06|j5q
z-l*5&m#Nyl0*BcozD&xyR^Z4@&!z538CYrrM{!A+7=4jyYK(Rc@1lGz#_t~<%H4lu
zU>^}4#K|3Aj0s4Ks;toM-Y#o?*t59q9aF1uueM(yRars$vv<pvS_N#isdRWx37{lI
zHI9r)T2Qwz(eeDHW{&dqj;kjr+NVGK?Z`|QhYCa`hN1U6)KW)va&q4MQX4~i=b7|~
zNjiJvt-#dLG4%4L(nPWidq~E(f754(Kqc3?@mIc3Oac#!bC<3v_-I*V09$6t<kK&6
z{ttMT5rlIw3PU!p?cU0hv=DOx?s3UzzQ*6z4LP}l=pqCTA2KT%WMz4Zq<+(B0{;bZ
zs467(aUec$vIa@^EiR|@e;T#-=)j-JqK8?1{o7Yb5{`*Bpl3sp(9MVuDDnH>`RB?|
z3waxSlKf~y@Y^Q$uQ#K*;XfkDZr}uUkpFLs`0saoVo3y<IVq?rkpFXa|Jzc&-+-oq
z$vZ{tT#No)v+~ylA}ERW9oH(*z)0!U(Gsell2Yst2H<z<jC<W{vOJMow>{3hi0qR3
zW5SJ)D5T32<>yE@ZJt8a;U>G|<}Tnq=R#XQlx_BK2PW2AxYDMc&&}%o)(=qp(S=1i
z2-&PT7~i~k<#fC(^5u(k6U&F!a!mmc(6F$Em&p!$m6l+BO)(5<9=9VXZqOXonMV{+
zN3|tK*;8xg8)WSg|L)^u(4FJLNsB9h=UaE(AmSXxm&ZkqR%34yu-nMbjH!4S&X;ez
zwOebaFjNTX+|p@!A|V;G=4!lZZ*MOH9DUhFVl@mQAyK0fFBuH6hN-7oSj*CtGAbyI
zta1JBhgv>^)0Y5$y<#at&9IpNS|ve^H-gNw-OB1M<~;n52bM@g{MZ@p{Dg|8!+}8^
z8fq2p^tUMYFuF*u!yo-xI>J+&s*3V%Id`sQQ=7e5#ddJ<v4UAqZPr$3-=6gR0#VO9
z+7qNOoxVMARCx0WGE=;ma<<+wa``Y4GdELi#pl*VQgk?@B}m9GFi%ubwmKRYW_;Dp
z8{+vXOnzq@=!&el7FZsWiXANqaddgQ^K)fatjcPMh_QM<s8u2!RSScMNFoLaHL?}(
zDlNCV5x6#<){+oA-2MRC9>VYFqVVvHJ6iIBP|SNUaPo{`u~}})xke`9MgT|@<?0s+
zx?UnPHlWx<=hJnpdu})W2CtJ3O%;l{4}`}$A9gh)L`A<p;plD*r@6Vh0U6TWx}ouV
zI~toKFGI_1I!q4Vbw$`SrVBWcjvaDUUitd^jx}x3hRki#FQ8*#g^L76798WDOI4Gg
zl6$7q3i8ODP@yv2dNIFiv)Axha5|zHZeP$T>sivd`8uBVixmjW>`P!P*IUC-e#gs8
zXxJ?)x?y5HTHpYrsZJ1DPTK^{NDJ??=)9!-?{iQPpL{jByE}$5K(R?pAL(EQhz{N9
ztlsBfcD+YBSoDCnOfU6GsXfv=46xpvJCu1vvl~dw>e+E{<E7u4$2Z<NJF!4wZ*<n}
zy`!;Si^)@dIbZ*d?OuKb$v?p~_e~@<5YlT-`mQf6+rF!lC6V8dy))UaqeY6;KtFGI
zNgm{i_3o$c+qP&F+-o*oK34t1J+YIs3neH6m;@y3OW->S?N@o*+^l|LR|-A_f5W;q
zy=+mbhtJSya>fIeRp`kRgvoIKDjp48i$4^bv682e&2l<x#S}DF_2GrGxM;^f!Ukdw
zhwZX>o9_+%{D=N(ey>NUl9jsP869iOF%=CSJCnmhz^j?d-l!+`gTQV_WUwt==?)h`
z{vY$Jj4D`&tK0XCi-+O5<Eq7vIKY$DlL|OvfA=Pq&EN`*ii&bp{#L=T!PXA_-@D5-
zDzH1%K(+uQDn8})xyqaM!TJG7q-D1gD)%N3Fh%;HoU6aI!{qj8a4Fdo7}%(DY#x69
z`4l(z^)fU%g$|tx<ZCH`yj*--qL5?9()OHIw@=JTA7@IT8&oYIFd-yd;O)3S?X%<(
zE{A<T`RLqGzmY`~F3+V3seIV;V!!Non?h7vf;^^>V3|&nARIAX#bxDK9XSS`llT)(
zWV^^mK2?2p1yDY|rm#oJgVT%chsOk(>8)Z}v)Qr|ovo`wo<v>;N_Okz+;JV-Cj?i|
zll1gsstSWGi@{_*Vqh8u$YvavzCY#l#!uk@k45)S+n)8+OvB!IHda8Z<_FZ+U-R<v
zEM)0a-^wMSsB$>*s%8~rF(}Y6<|C;*R07+>1*E%s)0D(Eb!lQKE?v(hK@Eu_CF*^n
z4SDiA3vV4_N0AyUbvwXV9&mpkM0~t{sqW!1#jDXYs+19#b^4yPT-@_AE}`tpoWQKt
zD${(^B$OZQrQ#*{P~dBDOx{Lk@WjdafZquJ1DwPD<oH4jPV`JqPee*sR*&ott2qVS
z6BpZ9YU}3XoZ&VRiH{9Rc0px%{y?6_#UTeA&}0km<7f&J!G&F$AlYvX`hXjq#zH7=
z>i}N~>9i{#E0h3LRrP%4sz`T-bahSS;wIbl#{#Pg;7zP#Sk+9qhK`QQYxKtPa5;2!
z^&_upCH}3~BRs-p<elfc8pANTWZoB=wTG?#p{h(kF`USJu1Ybg^7A7Km>BS~Jn7my
zyS*fME*$^}%YbX@YnCPbzR@O!;itn}<SO$eg<}PsrGyJ$q)}Kk!;`Eom%=TpE5`wZ
z(*XmDu0F-QvHXpv(L+$}+B(_sWS7FfxBx33`w-W=h3F)=4x>>UoB+T*T*>e3HR+5r
zZf}Fz<rcg1dH5AmA5M%PiS%Z;ueUcumt@Mo;+z22Pvc>XeH9myO7||BuYe?DN_Bp<
zgGf7?)bA!UWbv&%$fF6wY~BubbvrZZh{W`22Zl^*35<*dD#h9TxHAXDh}edY_b;hb
zim3SaE}I*0QrAkHzI_cU=Fh>i+hB5Bd;_QvVbv>df4I#!jTRWQPWh1^MMp;`GMP8<
zkMO$KcPuPuPA!xh*4}#3EA`%kyPQj<ASL$C7LI#FI^7Ht-|4?Q+wKehS`u82vhm+_
z!^s=C>=CDw42UG}Kp(YQJ04283_l*H<1C@Hy#iH0uJARW>qZzE9$EPp<Veud>VS{a
zsm)Ep&n?wg1H-Sy^%CdoEymlB>uz^_`Yly{(y`xU1Z=;Ul~2!-a^bl~7eCha`=M^H
zr&o+4PbY;E1X1*oQPs&^sTy8<%HyT-*{k+2a?LLp-C$v&jn-mXGo7Dw+zG|ue6<Yg
z2QPN+pQc?)V4CsAiP6{AB&{ZHW3qxU*HN987xAtycc`g!ih`I4&bOa(zOtc1)Y`1%
z?*!ikl?Fz3YuY-t9_Z%&41}%R8C1QAMvs={ymuSZ3d7@52o7r*OwK#&lxaVSHXJQC
zbaUrAQ9M|-q~_dxttKYQYc+Z;mO_j!ih=M!pQPDS?A>4jW9hQ{<Gp8{UB`ij=yt``
zN_cM)IgckHm>z|YJB(h_>1Ty%$#tP&bi4mWLw6AH2-XA5y$EztGF##Lj4oxC@J&TQ
z1JFWWT$eHSC(!z>><qQGLS}Gp8LGImI=PhM(5O%a-h9r>vd=lY-rJY&CS4mh_Ikyj
zHA*%#G=z2BwDdvS68$EDPCM9o!SOpVV$q0|ItU(=a6dW<20fB3KX9A!)5LNh{tUJr
zQPUB%*PMAn$&F7T^{RuB^{sx}aZ77Y4?t2wW>u*sIG#LZ0~P`b81U|%KJw5!3ZGN<
zCNM@8kTVE9YF%@9hE%@+gTWGQvw@!?N-n{Ml;73L$r7(Oz}WmjQt?zJw`Nm6@CuZR
zi`K`zOo)j+fQaG}p~jkGru%)N#G7+1t!9iBVRgpTpx%~!j(k`o`eY7ya5FDN6o~}7
zOagsUWV44WHM;#>#1ec>Dy^z4+vAL`molGKluK{V(2z{&-62?DZ-tdC%u>I5<a3!#
z2PM+$vzN^Tmu%BTOF_j8>&=0ikbQ-WEnl;GA}p0B?ZD{|k|YoItESFbif;Gydcm%=
z-D<lhYleGwABYr&o;))9?E@Oi!#lgJFR7b5?@)0=R#(xa(>Y;|9e#yn>Uts8n^JJD
zGk_!EmPMNH2@e-q!hnC~zI3J(%xe@L<VNg*maQ#eJs2^)<)*#dIXgx^m1hwr>3qK%
z-F$`7K&f%Z`|ZC9zt$Ks!2vy<Y+^o?_H>UxAjCrE8IcL5P^gmZvR5l}#)>b|i2UJy
zW;oPPT=4P+b;6W%a!?aG93fsMBW-5baAqh}@)MuSF}KAwZ3v}*KNZqKX<A23p=oSR
zNfxifpo%VULB+sUZ{PsxapsqrCQesy@~u+uT3`v*{+f^)Q>QCuY2F<7x#TKe&^|nT
zJs;~v+&2@c`ImX%^-*iD*nSi2EW*nau1eI+EcI>tfqrrIis)}Cg|ugPTO!e9@$1G{
z2kLRgX_L%0Y82BTiVz(6=?XxOEqrrk%xwDzb+I@1nnLoG;<O{#)e_+4N)}|1VjYZ2
zHr;;QG$oImrJWLgZSC3qC^Qg9@1G<f!-TR#$dUAgw(UB}j{1ZC2`ANiHj?-jjgym;
z){UO+FZ42WLR|{wc3HPkH`SJRKjyzmZJRT4;zz1T(Alkc?8rE1loZVgYZb}mXrph$
zVwo`)S8Z$r$ZX$fl*CwhQ>yr$d+C0yG#x42r>O4ootUro$qvPx1np~HADp-KBe>sA
z+Vy_xdR!!o>`bM#ecgK>U#b?qV>zRg67nH}6?=HN%62~)fC@H1PCO!7oT=OnFfS1{
zRc)A4&E<+fTjZopC0f|ion&abr!Bd3)m`hiK(0tX)HI_mzw+{OwdXa{$0@wiOF_1H
zhU2DS(A{9l3OsSS8aD0WY7|=NW7X+&p(bK-b^T%}5JI8^PL9u*G`yS95f8^#mM{1M
zFP*^!3&5a?8<vx0M4b({fPfJW5m9xz4IpoPI7trPsvV?otFel*)EmH97-3{&!SB?!
zK0w5N42QYgCwq5AYTSijOfr3oOpv%@gI1_|+GF|p>R_(4-%MqwVz@}87Q8H+#F8^w
zB14NrY+gg-7|`gz6U<dRwc{U(6Ibn7irOf=Jb7|<CferfiH7s$@M#7mqV9OfO>n64
zgJI>uH!Rxe-42&b7scKe#YqAq-L~gAKNPy`uMGr=U(s54uA16vOTOUxy#4Wzkk=Vn
zD!!z>DC2Fu-3J5V8Bt;g^8Yz`zQO@@;EM)tU7alswMTN#YbVTdV7%RQcl8uS5sJF(
za?Vzy-GW8HZY^=RQ=mUkv(&q8h)r_%4m|k=XW*MuhLj0dn$r%<-HD;5#TLu7dE;W*
z<yS@$6rKv=1(EVZrwIA<>e;s~6C_+<bh&>f<sEN|9xHo2V0YUlvw3#mlaQkB9gF;{
z>Lb->c6tOx4kze<x4LCsJH@is`in+YHVg9bXdr<jA6Ey<{f9qcpo08iu_lcDkMO`Z
zrCQoOU^%3Lwnp*h9rO<4V&@&7D=m8cm;7&gSi90h+c$t;7ebC?S3M<_LUx(T(waOp
zg(g&X(~tB~%RLkV7`;fJCRYX_Xe|05syMFCsc1A%p;!G4b$)fP8c!4J2GGEeeei77
zb)x{w6dR}(zL_~etSbnL8remE_ph<m&}hOU!5$@BUO;%w)0F$Q4Ve69NydfLguLM{
zb|~C-E|ijUXI@2Dc{ne{2vlrm3kO+}VQ*?L-=Tqtc}1saut*4!KcE#F9pY2EVn9g7
z(M4D<IQ`I=l0=(9)2y*l9op=}1TPsBE&-T)fsuefWeS32p_QgXnE7}qwrCR~l6z4a
z<-S^zbCDXZrGF9My;_A8MR$0HFH4RTsn?@B96XB3k53icp~Z_g;a9gEG<L_NYhzhG
z{VckRQf4cxIyySN7M~0aN^R}Hqu+&6b#2R=<FCSm?vDD_Qz+)Z1?AcjcA6gj9q{mv
zk28}J>&i5$lU=G3i>Sn0Cd?xWIg-2QuL>WZK-01wvT6LG%mUJ#gBd$|lka!f7cghA
zKzE)#jJIGFTe9A|Z=Yo*-`t@7_i#BI3NoY(UeLj5BnY_Z)zN57*S_Q_8ex8nD`IXF
zY(I|;XhzVgB5wWF>^)71^r4+IRmk18f~SvI)uq=L-Hg-XRY9Z66Z^zG9GEC(5g4Gc
zz>A5R>NsF^QcJ5jb$`(DBJ_>{+v<rfIimSoANVccR(J$=6@vP(_~>CU-N@ow*DVzv
zJDz6d&QG_Z(A8QT&3&N?gXBs|@JLGaH3QKr#k1@>ZgIJ@Tl(?Orl^chDc_2PVs{Hz
zu4@?vu@$hcwYHI8?_z#-o8EG=(td%?{|*0u8BJfIh`&^)v4n%(p!9l3n(7senPcsz
ztHqbGR66f6*V)gz<jNg-)A<Olh-dZEtn3)*!k}u5EL4gC9(y(I8yspaG+0!k8Z#-L
zq<6*vu3ftBi#Cf@%IdThF7~eky3g=k!}pZK`cO6u;?%3&3(=`pU=+?+eLNBm!xFu2
z-t&@yk90Yww1TuPvZQ5T;1z|_xdQW2JThq4NP<*sA8wlh-Nd(Wrc?-O#zU~_eWwba
zx&{t)6n-SBC50H93PV+H3vV7RHKM5^R0!!e>9Nc$RgG<~&(bO=lmuVcDy-PYlSkLW
ziozYufXON5LoNN{HETmrUxfPBOs9+ah^7Xe&}P~ImgmCk=*pz=7YU3>+STtt0|^h8
zZi1FQnT3Y1i(90=yp#Q@U9dTl@uSI~_sj}M4$852*1hUKkxFsU!`mgmLUGu178BT!
zZxHNfEpmPz&yl1e-V|xR#m*AP|7_LMrFxC?qD94XRM+K(0u)s_^CsU??l=hjzZ>57
z(2zY(4yi!_>A62NoemU_NZUKe0p*j+!5;`l(h_kmuUtBR9{U<P4hAB2v1qsj)*61J
z(8xq*+q9PBQe9AC<cl(3gl2qtr=?S=oSG5I_(l$TO`C&Z)zd7hc`PN1w>Z+G9+8}r
zj1bmVw`~KiQf~Y9Mv9Dv692R8f#@eAPGK_gvdu-Iuc86u+%@YRWoTP82E%rh$LhtP
zNp72kW~q9<-e^7oQKplts}CRH;>&vr2PzanO}TWwUBLM0QloOycqCmLG|x~POZ=Sc
zUYp2~7sFfb+z23t*}COH6Gaf1$r)Bx6hBIf<?O%e{hC34VP{<Ce998!rB_~pnUM+@
zM@X5~S@_i;Yz^owUibAIi>j&Ns+4FDjC6_mBCBJeaUitYj;(L?%T-=u#i`bZXDW1^
z0l^BX_Ch2KFmEPHv_;ef7#`h{3f^u+BWD8~nR|cBODHHJ{1nBR%Z#a~^*g{!=H&ax
z=~S6*oD{qv>8asjrRqKGi*A;h^-|D0HeluUaXr6IjVS;CNqzvhb(!Y|wxRvE4Kh7(
z@vo#*oND#`07~XRRAVt!5bUtePOUp%5rBzcKtZdry56G>Z4-<`n_Sk_$omm}?D{x|
zcIp<xZk{`6)@gNB-l4Sj8WZ!ItBlnpDe4aZ@hvHe^zZwYLu;imVPX0Hp54-NM8$15
zJD4C=g+Ar~>FcZGqFTGQX=w>1M5H@Mx&>(jq#KlO7&=8thZgBpT6%`=oS|E~lx`)Z
z`L^dg&pAH6-#PrXhab$|`;K+5bzRq5%XCe`4!nPbt|cRFMEHOho6k<W^CBt@3ZR+x
zb2Y@vPX$5kgq{a?ICorTRV#_ca~ELna8j+ir~vSVwCt<jqI&nCC@#1?mf!~fDinUB
z_cmJr^d<lpn6)^(q@?}CueAT<{kPcw?eeF=7sET}(X?^-&$@HuVn!N0??SlQsj!BO
z<Khi{qY=HLzpq#V6a|61e&OeoB4CVGF2j7w&E;jls)uJg6eBJot!^5SW)Wa`1c~fh
z9fKWjRo|`&IQlhzivOf`uNHxj*dPV(NzoYD(^@Y0M%t}9Cbq>;G(ViJxGqODDoOXp
zWS`DGv(qw3w`aJF{9CzKmo;2klmQttF?^&kpR)JK4M(e<>#hDc)iSNL=Vp?;i2GoG
zn)W$Gar_2q(O$4d9>Z1Tr$_3DPbCx`n}f*i7s(ho3jR@Hf6jWmB_gla*2j73FTVAW
z{lVIV_s)kH^tOo7R5qxTG$9AXc^tsMnoeygszEv#J{+2j%fzScsFiKZL1Pq@CK~>V
z&8!Lib`zA3^1iJ?T7dWub^F5D>iBw>H<j0}0Kp_K%GX+hb#S{sR}S*(k#8CqYnn-|
zvnkXW-VN#;_2MO{nN7m`a`EF**MXCXVnBgRbdv{X3U3+b$F-wVjvUvFA?H0i9WM12
zb2(g!5T}-F<fSP7OJfomSXny*MAsogm;UC%()PS$HAmW-KggO)HtJzEdp4X^-%#1_
zV9ojJv01i0Tk4119yu64(~jAAKHkA~au~Nhm951iG5*#`u6==YyqaVicX;>y`#gqY
zpw>_X7jyf3U0L34TE^^3cbLRSg(Hv6&j(rnE>kcWGHBM0a<0{Y*=}0Tq1_USOOhE~
zRy`k#ih-{|(H4e-zw<oDM@zF@8>`%NJG*R6f{lb(ZPMH&%&OHcUCyNpt7K5e%n0f?
z(u{++;zkAt=%TC8{!aWI7+{HWcB~c>POf|d#!x%o1jIx;xs6w1_$^XQ6l-bU<iCv~
zD=nBRoREeKl$u0uWEPi|=&w1TNVJLq<RG5;fc0X9iUFOhu@4=T(086eL}+JBJ8PNk
z9O&-|vi|N2pw`AwPxkYu5Pmr=x0K*=qhbu~Rg>^j%0;b{$h(@Wdq^v&5A<$fi&bB&
zjT{$YMq+MbEkAOHmRr}E1BRo^!s3-CXU8$R>3(+#=!0IfATBbNq&08KBNppPk+_DR
zy_<@kSbxqU_yOS4EG81f(wv&6lHf#Ji`PhJUcNL8ejbb-)7?XhPtJ+Fi48d5ef{|k
zw58_Y;d|xE2S+<w+ZYE-_LL9T^pf~8BLw~Sz(`H=k7?81o@-fin3O<rvU41wW!U1z
z<e)xycvxDr+NN_P5g_kDqbo-rOPD!*8I$=qvw@wSpDKb{cIl%y^g7?|JcJB_?wJ29
z<;DE7p&1ZlcmfazR<p#3Mk<6+n>O30GrWo~trxL1DNzEFIZ$UXhZFBwf>94_mbktT
z_sKYWl$iQ6XUCn9R5NS~KZrU0G1N#UMJyC$(dcnYc5`#1+j6XGK9D?`oKRAy3-$H(
z$+u4HC4cVaRR@zwyu-k9A8@K3MoCUC1m8hceCMIbnRf*6)CT}-<6=IXS@>2eRbq3W
z$}f8|zvip43qrtb-F{8tGUlA;WN`ZZcqVlJ`VMm6+v<}amQwTZY(ZB*bHe|XSYigI
zV4cXWr+($s*lhP+-)^`k47`B}6rIC|M|7W)c$Se65PoVdHZP-*DE==gcw5jqm7amx
z|0_o&DuM=xaGv$Q@J*WQT%dd;wBTSFu^GoBH@|Mqk0S;T(_0v9@pDiH#U%MJ^+q4s
zSLfx`CqHBU5~n3nE$GuY(;`a}s(waa8Ke4MMh`k!y)n#JfC}zUl$gJlshypw1PNSs
z6;O*pker^L2KlK!hDhjJ`H>p@VCnGNpFb7gCpIazyE&h0NbPhbbc0{OfNr(;{d!h_
zCWg59M(^#Eu{TR*9W%<-jO)f|t!nu_QU^-CBK?>Hh4hG#jQ3I%kwTxQ=s%wKH7IRC
z89x`S`ug~6Qw#`c7^95<ux$3EE1xrvcb6{is<MPRo^lc02NA)5vT|vE-c|2Wo9SBb
zMa0!eNzLyW5zlyyk6t?#b6Jh=8pVCq_Z^CkSo=)`lPUI-mwY>Q)e2CSZ+isIiR6Ev
zb;;S5848Wmsrf^!;ZIOlWS(5D-dui@HEj05gNNVODl@u?s5Mr%6}Nwj_Ff85XefL{
z2>%-AZAG<dIFP4DH=EGcMOWz%5VQCEWH(ju0tJMxRkQlXudee|-^Vh^whd0)2RZ{+
zZpPRRpxjZ-L`G4#cChd-x85U*8AcLUiT#x=#Ure!z6}R^Z7nvj?|0XL_5Tm+_A3_C
zRw>gq`$96UnUSc#4m7>ETBVR0!`MGwu>5TOn0ILBQ=MQs+J9}plLoqXpO>^xU&Yw$
z&Gf5!z7~A(%i$Qvt4fXdipfXGXB5$%$isU(txa5cwm^BOgLVeyA}kUo1RrF}z{~7p
z_?u<rm8JgFT3QkSd?8tkjeXHW{Quqyct}9%*LE>gC=MliQi)bGNibedW-s+D(pwP(
zQLBM51}_)0EIz<&d|idIwMIsax>KK*^wBl_?-71CiP`h5DEF!cR+dwpGZr^(sc+VK
z@GF~@ONG*aRC27Qreqc@`A}ub)VT_?EnoL7)?u(g+6R7BweS`6VEu<&T>kVuCH5*D
z{<so@F)l!&2eVcY8sNlaE}P+DdI8nyhQ8LPPVCnBA1pJVy$#7WoEh`zw<e$S+?54D
zg?Ajq<%#jTX3oys9^YnS06?M*4riFzo3U$~6a^~5Ip0dYPE~z_OTMe6d~&?{IQj93
zmHFUyL^P$b@(C1%`o|apg!Bu3Zh3p9$=2@p*dQ`iYXo-9t8m5|;zXvu#`EVz8d~}#
z^b?wC9NBnkKQO1d=B$G#odfhLKwTuh<@csgp*wwyE4=TSNmUzP+nCGW&TvmUO$PxI
zf#rlG6GbS<@BE~eOvs)Zw$ZchmX>vVj*`Hd*x6{bSXDTlHz#MkSVbe;;z)u%oZ0#s
z*#y7)O?7}lJWpoHTpjvUnUUNK?D}LirFB3Ch@sW06&V1by2&d(?4<x6G`(USsJ!Y>
z?_Q(l1erj&35KWVk5%5aiZXB}piN5VwZPCW(Z54z%79BDj08|AF4MBM7Q&|A_kOH^
zFLu3wVuNUaJh=4*B04M5{}O+>R)|MaKQ8~|p#AOjNWL<Tmyb{WB=-#GA8Y6dHlh5s
z6Wh*`nZ5|Z3>z<Y@Yk7t_u34lk69AeD$3M49lt2==Rgq$xfkPV%(J~(w@D))rWCO0
z?iy2de8!vE=gqK&Z73K(DBw8X)$d@yl-DpQ%&7O+)Fu;B9k;|q<v3q=zkDb`N#|>l
zKzXKdi@nW2nwYXgtq{^g>l)u;vmMvrYF{X80;|4eEVNIMm`6JT!#-W!fD?M8+Uv36
zZjrnpQ9SkXXq_^d&mZNdXpF~dm=36dDzkCFJm3yiG@0Ap7`el&d)FJhw9#BJDj?mv
zAHZQ4PSx#SY&apmKm-r}_^j7d7v`35L)|9nIY9fznmCKW>hbhczggFt8VyJ*TCz<H
z=)YZIf%*QrZ41(0>+MEKx|KXH8gkdujA<()D>0b7>HfewF}uh;;PZaQqymyl1k|Ss
zW7Zn>a~x6&1CP2rh&#6-<<C%Q-+D;}@N7rxTy3WrzVCRf@Q=^WP}f?%Odk-R?O#%X
zk4}vyCO_3S6t8q)Ep-Ygk=)M`waAC<i@C0|*ElYrwl>vsyB`W#?6Ep<>cdbZCEJ1W
z(~rb&HvPRU`*OG8$w;Gtp$7oT4f4D}@#CwLkpAB6`%N4ulO3MXc$YfOiKJ<64X<gW
z2@Ct)_s*I<5v>dWf0O;%5&FE`(E%+KjZSrOp0&CAZ5AypE4H|?IN6U*%!#BcVsi2@
zmho5ZfEe#Hnd`<7o|6-omK6|T0fUInY1k07Gv)O1hAM!@q^0T1@w3i_?vH&52$(n@
z_!^>xMSmr%c%KyoNKaFaGUL_x6cPK`k<&dEeF8D@&2S(XE}Yy2y&C}7j~9r68QZ4w
zqcxd1{?hnjwE7szLD!A4=0f9A>_gJ;8vgO@dWMwM?kx_NoX=8)Q9pkCYCT#4I;9j1
zNg02oX(7HfPW8<*fYhQtUVY=6`%Y+ku(%x1+L1C^4x7uU2D@LUw7oaZ>UlOm#b4SI
zV3Q1#PtTdX<1^4c-W<Izp^_OW>~8yVHqu0`RgzM(R9kOCBN*vt2Fb33Gg*0UfQ*uQ
z_s9sh-$<nZ%yQ5XiqDRH@TdIdOBm7ffJ?U>l#Ry88x<QqH;~|@NriihcC_3t>j#-g
zUOZ4RP{)llZw<j{vtdeKk`x|QR}|#)4Qko7{C27%SC{L17oBbTWDZHjlzGtDD>DwV
z9CO>plBM?cU8b*O*=)L`e3p3>U%gcuRU=p`8kRZ(cklucEo#>3ewab+H)>j1sljIX
zuN^>>5G8iQI<(qv^Kd{M$@-9X)7IW`u_5d{fK#fGzm)r8uH5-+hXv3s!SvfHs$$z^
z(>J-EOb#|gWL6Nn>nph*WllTtIXO8{$7@SJ0ZWt?3L!M_qg9}yD?Nt45bomQBAJMf
zAg9S`cSWpO{AQAX)1&z&Z=Aru7;d{EszO63yJ9?Z{%n7oNbLiS+gDj%HlcCJ+}>}*
zWmy0%3^D`S-OV4MM|aS_UV?}Zq$*{Lp2Z<f0L6j@F8KxC1A(HLH+VZ8gA;?<H*ccS
z4rU6dR(eKP&ODCM7!sK_ZW8L1fSzcAvXN&*M*+7u0i3!aTz5_ZT~DMD#xkAGbn8+x
zPWU~R5FAp@mu(+jDjNRm2G;2<Zqmrua_%S!NVa8zG28)tuEMp5{Oqp8ce|#W)|x`K
zW>&<lAi7TZ(inNVpgX=~Oz`m$AhBW7AyywA^}4z)2P)Puntq0~Gi$*F0kE)mzFeMC
z4mV^FfStMkLYCWa^~ZFbx5)Z%M%j<@FUUP<Tz7Bun?#L$q|MQWGFwCJTaXV9s~Y}8
z^N8x995!<;-G<?*sX-Glq4x((xd}J|f-^rZ*@dkk4*x!(pP(qvy_odnJ<wn`U6~!N
zrp`l3`=LjCpm`dst^jQ)EM_jWk^T`y(M*$%_!LpM4%uuvG!qe4mrf&-hD)=3?V&F}
z3ln^3u*8gJ2X1E3LL3f^ILt<i(>c<v&Mr2(>ZEM>)cJleBtLp%d#IT2i-_#ImP#B*
zAtWLyTAq~|H<^h9eS9A1w|NA<o1oQVPwqYsH4`Y(`2-;~;MdvUs<D3Kz9Ya=tgql4
zh;@5ai4W8#&?vvrVK&ij7G|Z$3`4i6Epu8K+H354uRFU`2c{^}Dh>e(qpTcnxfW`+
z;0|RpMy3fk(!4D%e^4CB(war(xYSZGJJpT(rS0Zvp$X7U<a2QjqSEq2m>MB-vbDE{
zer|r~tkY3lm;Ua<L=v=R{**!UlOZ8If)u_h)VeYYRE9t5FX&@fqp}eR?hWx2_I%R&
zo?)cH!Zq>{4~--S?Yqfh4GKU;@Uw$mhg2ucWIMpV=4cOY<8RE=y+jQ`duzHsFHr&L
ze&V@w9{BqNKxjj8Sn?ldI(}<G6%f#A8Y{zNRL!tye}X6h#llk4?#iuD$u;F7AyFDA
zNK0zQ3SbRbAX8CMeg1TvJ~T;)%0eIH7xSahv`1&@gKNR9ULDG4vQ>Yo)_G-gBqRjP
zBU+1Fc2;L4;AMU|(p@s~^-pj0ODoNbE0Oofgw_GRRl?hzg%>oe<z(>d=E*~E`d=NI
zz*PbWC=F4>$a}3p8fa#Ejoz=O2&t}skww2@(LXkE#nZ8)(Ir-n<Ei*uSgblAN_tK@
z3XzmH&rSW1?_7MqR{SEar8o5?ePClt6BC1gggkoW`}fan>Fcvsxt^-eZqIcFQd*G`
z*b+PMd~1Cx6^gyN5_zvUZPPkUl-4X;tyH$!%iC1JuulG^n2{l|VXL>2L=t+n)e^G#
z;c?d|o{i_UlNRk0I|84T-Qc&Zt8^a?>tW8W!<b-7YJurQN)fd@TZ<4GX)_>CiCMo%
z-mnp=gN`l%z473JQrP2RwVgyk5}RffGoa@>cHLrnEIa8FFO&M<HP&~wF9l-@k1aLL
z>ZraG%mCEUjKVn+JFQf8oQRY0L|LO1<NRG*O|TrUxk~X=S!X1<>+=#XwX?Os(s^?<
z^tVL~Sc8=^{g&^B>yJo54ztg$9$Se6IXMwI-Krm-$4YH~RMqqnJX{+tKos!srqtVR
zxKMV`(rRTzBjR{GRowRHf#T26n#uaSPLZ77JY+4MoCHljfH(|3mOPMK>$|UIqTk@r
z<b8<`Tk9z^42Jj;n0Z0naomfdW|F%F|M0=u;+Uudvf>Ui9unHvklWYDL)2Q8GxL`0
zRBytezZ@c7iCDT$M5G&E+jBM54>GBj%N4vwv=ZAn8O@!+Y9l4{((<Wikmt7om#JrW
zXZk+ytzg?p>Kt}Fr6Zsuk9vn|nRJ)Y;xRkP7?`3L?i2CcW=rR$x(TygQnHUS&|-Vs
zTf4zcA(HYMkMq(5zH1WD$yK@W(dpaWliu(h48of(v0!(Cez0e4<iVk+m>3NwN|i7v
z*Cn0rsr^O$yx>A(YtF!CH{f)3$Y2BJ;;LseQEfqfnNIiW^g*yL)5c&11+dAV0ub=Q
z_m|ZC_S4yhhSt~e=Kzfkg->0+uj)X@S)Q$?@R{Wc2=KBRD#=Q_1Ob5RG^_HyMjWhg
z;^N(<)D^Ye#^bW14X%#4Zk$k@`@Hxwj)sPu@*+UK6woV0cFjd{C{I}q7l3q4*CXqJ
zRzfO$TA{igfPj<g<;#~vWv)kPKLtlXD)Wo6_>>~!8vB+y*Bwq26qK*ara`T@e0<^#
z(J9g;uf9J?X!iZl(npMe6(xt%G`)>pWj~6`q>_%v?Hx~$aX+$*N|?j)#pQLT0lt^3
zK7UrXN>s?W!3#YU`#vni6OdM|jmffqApbK;zVStgp<>#r)yhps!%PXgI*p7DM^qmB
z?zOfCJw*OHo)b+&lNR8^X;Zw_B9I<_e(MS{z-VNp5k#GzpC33M&7SUR(RPR${D|(L
z$WolDT<N|6DR=1}lJ~^DYMm0H5!?iIbV?CYQl4Z*OdaI6{U7Pvuku`ZR5U~k)m<IF
z=xNHBgv5tzhX}ppRK9hum1?$S1Y1f7n(NAA47EyzWDY+we`97H!uO8#Sn2UVSJICf
z+BCn~pWm(n3ld)!LkeVD+ecI5Uh-Ke+ec}=(&&3I{YWLa&7LH1g+FBcS!P}l<5>}y
z4SCv7B}KBhImi6N8^rEO_y0F7^}jdplEth`72CC)tj)%am}Zr-P5;0u?xh70%dKLx
z=a>usZuc_fA=??N6UoIB^Lv(If<r#j_6j9^dIA@bhR;>vegOe~QGfqANA`rz9cfLo
z;V^BFr~DBWmLUGw!aD|^C)_3l+xfLcYM3oHq>I_LA{l$%EGzm&Ph{ssMk*6Slo?5b
zBUS_}EnS6jLMzms^Yacd|2?7q6HomCDu@Q78On_CH5zeChE>2&VK6j)<WXo}DU75h
z*Q^Gge;SiQ+PMGy>2R*ej;$h9qV%~nNxO?JQ9!#kO8G41u%U|2DB8<rxm3&@X0m^o
z1+N;cI$0UHH24d`&_QupUKT->LcU_SrP50~Nq+RR6pj$QKIam+a|yV@MVF?d0?V}2
zUOlnhlxEk|MXi}lL7(^)AF_}(a}7zF#)~@ppnn^>F-qjAiV94NP&SJ0_S}J>LD~vo
z0o`RpX2CWto<DP-;HhC)bM_@7`3r4!IhM2gAQCAl;Tt2|<!TtEc6N=fXfZ!;tf1DN
zA;hnu{NDg3d1?n@=aYleXLEFJ+`>t?W!&|UC%Zw+(w*jy8=JVdTT|Vk!IsG~|E7Ld
z6+^Df3Uw1!CJcmM=yWX!e(T(p9%Ob5Zmg?v6V}2{`?t4zFGIZ$(Z0+h)uh0@MA*Rn
zu=Z1W-$#=45}A&^U;VY;uD7zDG>`<t>8E83G3{t8^zLixgkCsZn53uwvhjakCr|na
zot5kJGyRkpNx}GEvm=AdZb7(GDL52EGLLFhc+7be|MfjVfo=}u_TeB&dgF5e*%0Hn
zo@NkKJY=mX3<nFlP4(bn?ep)$`^$z%r+-%l|3X$tRI=+YLl7+%mDWIS-A*<&=Jh{r
z$A5R_f2>NNRmjgbUFkAW-kOMBFSZipL1e|+_1pZeZ2A>kd#yrkbcst6KmdZ0wD+;=
zdWR6q2yB(ngp+bb3%hTB07&|Gbs<3P`SttP&gmBa#_*lve_Qs{fo@XNMg|xZd?uA~
zm~<yyb11E+vvy<xj_J1ML+L`BpFa`LR@nrzXyg}GeeHY;s4Y$SJeD>6#&Q(^B?5F1
zrdMeRm$<zO9+tSB|Cy8DdUJte)*W4)H26=ZDbP*ji5uN$p0vnp#Y<FeAUXG#T2)om
z-;z?;?fH4CT25vx25qT9t+p8jk7eZGD8!P{bzJ;$>(+R|%3keK4f9f|fq+)NdGC9Y
zEl~y0z+(sUk{ZbPO_&(tsIYE`F%%;a?tZkcjPu@<oIMK=Vi%&btN~b<sTyKb0eGia
z1|^a-8ABr@03iwl@?Pc!YLk)y9gXx9bc$sBpSIK(3G!&%`e51}phPqp1_rA`5fBy@
zs^?*oa2i59_GW2lX;Em&B5GDwR^n<Hkv{lep4!@L6>G}?gaH8&kts+vB`5N_BNT^q
zVPS#taW@fz;**di$zY66Zl&o!V`iD_f)i=M6659vzNfpAw>Q@sZmC;_xRdje^o!Wj
z@@nisY&vDQde1xG;C1fKR33ETaD8xGXegSlahQuIU{_^mYHprTW^(Tm7N`!6h``Ct
z$swMIQkb{uvbHDEN(lYO_d-I3p53Q8`__7k2*DygCRAtw99FNbyd?XUu>Huy)o0|*
zo%FJP{{Ctoo**;m_KTW}S6U8+Po-`ee{22$l!XA2ei=M~C2-V}Ccp*YRv!V`Iw6RU
zot@nnY_-nuCJhkJ9&9r*w5Qypv&6->>`f>vInq93WHxC>%rK~vk`Vh4dc$eYuFjA8
zRGlM8I6e>3bJ7C6D@vAWZxr=d=q%ty(zdBf0q1K;x-EV}K$WPNfZJ=*r*HAKOpp+t
zY!7H<!V6uReNNO>BXfru+<|yzSb{F#=1L#*=pSDjE6@}k{wY?!@zH%dJ;D&cC9(w(
z6GD>M^|E<sN8kKB>k0XzUVi`5-mpl|N#4b*9*NBW!O{4{l-RAmxzJdvc)43STt%P2
zwI+UjtRXh2oeOL`R`0{r-o6niF!43va3!3(cXjlW&3SD<GaI**qA63v31Ol_izXrk
z*Bt!8a!?PT1{o<>fu`(bl%!zPBQgE@YywJ^X~<gjfJT~J5~tB;@2#=CC@rm-6do)6
zT!!48u=}-jodnk^7w_y!qP7MFmb!rWP}3J!<(lVXo{FKz92jiaVVVJ@J-wD-Q!Mr}
znpNhsuHGo{<_L}Gt1I1vM6WDy|Idsr`g(er>H>U0btTqgxmW;^1U2i%KjF=O+4<&d
zJ<ZA9BZ=lIMvq2_j<GlT49ubvSo+|tF@}2_`uE23m4ioPA_p;&<^RE|zRSnF0*DJ+
zQCMrjDD}Z;j$EJq8L(<eR{S?IJmWVTJii%B%gC^J76RL3qCfJXkUF_oxE+=^j<F&C
z=VG0^5?9}YSu4RSvUyx#Stc9+a$}G;QKY4$6to(FU+uo5{d2r+#`A3-_9t?50+u0`
zP7dE<%dWV@JyrLP(mSXyF|R|3MSr5=9TDd*NF?mKAG(}DiR?OM>0^EPk3=zT3~<F{
zb|-=`H-HRJoqfTOU~3nufGcQfffv?0>V0<e#pV4Dvaao!<n_ohCY1WR4nf!TNTQZ%
zP#8h0(~>xYp%T@P{RIt_lbh?yC?iHT$8#@gJ>}~k2{I%qC9Y`TyEMz?Xka|3^(bv4
zF(HjEdk|kO;d15Ev2-k$uDOQr&Wr1i{O2E~`o!S9aZIC?R;tZ)kxC?aXMx_|zXWDF
zQWC~p0tkB1YK-`WJXV*ftps>kdM8`-f1&xmQ8W1*G{A9>0y=w3hD?+5SW+`HV|K?-
zbpyL9p*{Pgg3F`@cQA+-$d@<+b_Y=W5l`zGyA^ydsLpVN{W-(ad433z9@JC@0%6}L
z<n4b!$PCvh$Lyb}w3_n2QEZ8iJ3I|KyG*z)>uOUsObIVzn1s>l#ysHbGv-U+JXuxt
z$4cXOaM7I<=HcbNM~i7EDQ!Z2$<=xlRPVY`WDX`~b6WA-o7K`IOk&ZH4TE>6A_~x<
z+%>g#lC=>Rn<Zr%8yf}3V#=4q&E+PouN1Gu-M8;?8aH7c7*apN-gRiPTBxnu=p_lJ
z5U>OEoWb^|8+&`9c(<I@DM|0c_#J{XG~XPp_U0HMMdXz;;?6zDvZrNQhN3~~6C1*?
zU}q)4kS+wZsyTg69P&yWS-l>7TjwH)>0V7ohKQ#djqafg(ksBesI~Zc8^BX!|7l$V
z<#Z0<qy%5T$Ek`3)&&yOA|DF*opE=C27@48pF-zqo!HoP96I?NOxV4H=gGPjx~8FK
z3D5mjdkFL75;zRB9b}mvB-Fhl@Wd%^y%A0oa4O?vA>>p|7kp{YXl!T*Q#@OVk@&1;
zNCQ#JtFqz1h~Q`Js78ar?jviDb!i1z8--!fW>N&_uY|qKQ?nx8u_er~c$GR)iMfxU
zCTTcae`Oj}*^p^SHF`g^`FjEwXjsS%GGeH=hrwT1!56RZ;J@sjq})7GNUyegFPEWs
ze+^5?79ITNdO3m%VP~9K0hwtaS+xlX0ZtWL1roU#wNc}D1?ZEK=@uJ98FRuZ8^5`0
ze|_9~-3C;ki<dAVFCx3@ZBb8P)l%1PL*UJn8P=PED8SGU^#&uyjCO=N>`@F5hVl@=
zWIgG6aq#VO-gTIz_)FHS3oKYt;@P)}c^Y{kImt?S5@cPRLysm%GqCZ4tLIR`?bJXr
zC_Eup7p+_uDpkCFtTrz~7Ht27seO~PGnp%>q|WXgHAy{!+U!{gSqWH0e(LgKryOM7
zLtqigkvN%65k41H-g40=7@`@*WPt18p$Q1~yQdE{xb3^FanE5{l@sdC>6TyF<UmGA
zOc*Xz_q!w_5}6`owsYOyQRobu!u=K!(JMrSDoE|I;4t58KO64fJ<<O<YXA>On;Jfc
zs$7u}OC{ogyU^&VLlGS&Q>=#T!OJsapm=o~-UtE8lWfbZ83whswhH&H+nR#eeRaZy
z=*x(^27@0eC9tB8rmPzF&EU{Jh}dK^BaPL-0Xm}Ta8fLKt>EE+bo-`>RjV5m#1ykk
zd#~E>P%#ToAUw<;9Wu69gF9s1Bo0Q4(V<;6_j&E?dWmr?b8vL6+{Fkp;YM%k609dn
z$c=rr7<jEmo<K=&;h)Ia{qN<Ps)~y*Ci8o<16gIo(qA=qS=E#y>eyO>7<x4DW<myy
z35Y%Sdf$E?4SDIi7Wclzbwfp~^wsr6ozF?pO{@&d&Fg9=?wVPWKz&Dk4tZ~oCn?jy
zf0B&<S}A{BY`uMLFU`pLr1W|+9A1Vt8kLSG;<5W&X31xVBZ3t+9FKOO$}U+F1}}Wh
z9tzj@1WY}vQM3!^*86YPW&)!*^bk87C^P>n^Ksz=Rr@`DEiL)b0A3|)yA0(J-I*^c
zLHwSCpQ0qYyv#--rK0v30Y^5cN}x2Iry+CG(-fI~HXE|bV>P5{T3z)KYlK!)$vGF*
z)}Qe-*}ngUoOtja-umtg&RLZwc4LI|m|Vq4a*fjxeto_4Y668+CJHVE|1+T)l3O;S
zE`8m@E;N(R0SA=qD(RHxq&559Gp+~2v^bIonpawrWkwMw=-7o!k4?Att?2{_U*$y$
zt|g{vT*dbcZtXI94n@cQE)V!C+E7n=Z7pRAYIOc8m3OyyZh4t8+vjAvPgrLx1J6{A
zeX?CWpf8?95vf$ax`@aUF04%q%4;4>6L?B2%cq0q5<fU0-Id_yE6M&AF!g7v3D*^X
zB^+D!k(AcVi80%8VR7e7P1arX*qv5$$Y;u~X^Q3Af7rFGe+ZvGnk+R?gxp_Hu96!4
zY)&k0Mj%V&e;n(QMT4^6`S$L~;Axf1(54UIMfVZuopKUit6Y&sSX6|F`JNW$#1ks3
z8hZEvRcdvC+&NJJ68$W|KL<A5q*Vof#mmmtscf5N=8iH*!FYk{+uGXN**sN8es5cl
zX%{A+tlqr{QZDVGN}1dQnCtq0TDG(8GpT`VCgs!+z-#*mI9l5nq&z3cs2ETDkmhji
z;6HpGA?=|U|NZR1Y%QQG)(*?p0hI9%(dm~~I_iCtRXk^qJn#O~ye+ZR7=s)(47nWt
zTj2O6VBdcvjXN<f0dQSU;nfX*r&&uBjEaitUW=8j)LU=gz<7Qd)CA^2gr~|t-Rptl
zEkB&>;r;s-3kkwW;2*m)#DM5eo3<KrqC@GpP2B&Y@NtJ^mEeq_YM0BoJo!wUiXW4m
zBzv$78i}3l=x$dl)cyuoA|g1ifWd@?WuAd1Mep^HNr#XOs^Mr9sK}HXH;=$9lq_i2
zU%k<wO*Z9iT#2{l2;}Fb@#^_9Ow7Dx=#f+=M)3WMxKwa30XaE7HO8o^Z0QZxZC7Cg
zO~mt{oKNBI6}mTl=;H$|rE)Zu^Db&#rh<GWL8X^*uJu9|W`f?dFSsC2I7A-x(I&t-
z1gb@~K499%ko`k2MD0&NV5D^Q1E`rnY3jW#Pv>GOYr4SZGY&X19DWzV8UkWTv4h9J
z!t<WPSxyAB=~s&EB&x_jSO^b7$D!^h0SPuH=}I+ZmX~wEEc)L7>=Rj9Eu`P8%Vj3k
z4nG1LUu6~fDU2hSvdSs8`u4TAMom0X5XS@6Kw?5q_ye!`I<RiDPxWI$QbO$@_Ir9r
zhxD@SK{6)+>g}T_)dCn7m^E^5w*Im+|8w!K1rq{Z0mzRDCI(qf?Q(?jmU{N!@yHv<
zCf1hy^7v0T6-%W%ljf5<Jmdlg6Z5s-!_cm?Hy)p(6O-&g)3L)Z09x1Dkse6M!adJj
zqoysd3n9p&T)rd2?#KYys>_Xd!4Agw+cEnUMEvtw-U%(UFbxv_Chol>t-6oBDohOI
zO1cDEZs~~CJCA!veEBEW{(t|II`CNW$rW9{r6){oYOOzMe214EaV@<dt$Uo_!33(A
ztxT~lesQ5n%;PCH)Hr^NEA*$-<2UHxkB?q1Xy%<w1!_*N-Y%FLtp!%{x61y>yZ=xe
z>8C;Z@`?8QJxF`}>#U;ty}kc*@&Uik#SR4GknS#|N&Siw@1hrGIsY>Sztsx_W+c}M
zM3%2RtND6-3btbXPca+t44J%vZk!n14>0WXD?B2tIInV{Fo}O1YXh{gTCx&yjHl8s
zjj*B_?EN!q+FW`6?Rmb_V*$@2$Otsm!kDZ!5j&(8f^q%pJ;u?-s>#@4<$4zrXfO7x
zEgb<UXZ-m7*DrsW@&C^S^?l4-Kp#bq?S%W8-({JR_LLVtP7RqKv7*TRPyXj0BR7l|
z=mv~#GB2|3yiBrb=u2W#x32;ijB)MI?>t}yA%%Z?R)}gF1EY#iR8|^713+(C1%)Sd
zLM%y3C`<2@vvp09|6_ddb1?=MWWJ8j9m>~{6ciT5RvQHY4Q}}jP$^1Yvs{ax*d-DF
z3*H5&@{{P~qM3EDx6}ym@7|Sr=BByJ?*bx_(G_r;q+=B#l-G^_2aEj&)|M%bQbvpN
zZLapN9?V=aQ`Gy*-d^eDOoHg3i|$b~1tn$aSk+O;J8K8Begz6nPR>4BJv)=b>bl7q
zZ5<Isa<kjal*b)#_?^+%lz8`wRVBT>!s-Gd+*`7_@%Podd)5nYPLiv9uqdPUY%D1A
z$d9V(Jb0rO?ASi$K+Ciz)lxyK5q5H?PR1s)`XgS#!VhL_)*k-(XY>Jw0%hn9VnV{R
ztlyXilMCS0bW>DQSzr!9eNX+&(!=PnNN;^Z5tnQ5HThIf4dNlCLxN|#<-qvzZ0t_V
z&Tt*c!%`8BVQp_Y8-yrF8D;%V-A$yOq=8v<bWNX#BG0-Fc(3QA`^3r+Cwej?(W<y9
zhu18VWGdP)z%T$&{h<^jCugwspNIBKoiYK?uI~Y#q-ZJwS$C6=fFA`J73ngm7eW6I
DOO`gq

literal 0
HcmV?d00001

diff --git a/docs/dev-tools/painlesslab/index.asciidoc b/docs/dev-tools/painlesslab/index.asciidoc
new file mode 100644
index 0000000000000..e55424baf3142
--- /dev/null
+++ b/docs/dev-tools/painlesslab/index.asciidoc
@@ -0,0 +1,17 @@
+[role="xpack"]
+[[painlesslab]]
+== Painless Lab
+
+beta::[]
+
+The Painless Lab is an interactive code editor that lets you test and
+debug {ref}/modules-scripting-painless.html[Painless scripts] in real-time.
+You can use the Painless scripting
+language to create <<scripted-fields, {kib} scripted fields>>,
+process {ref}/docs-reindex.html[reindexed data], define complex
+<<watcher-create-advanced-watch, Watcher conditions>>,
+and work with data in other contexts.
+
+To get started, go to *Dev Tools > Painless Lab*.
+
+image::dev-tools/painlesslab/images/painless-lab.png[Painless Lab]
diff --git a/docs/user/dev-tools.asciidoc b/docs/user/dev-tools.asciidoc
index 77a781fd069e4..0ee7fbc741e00 100644
--- a/docs/user/dev-tools.asciidoc
+++ b/docs/user/dev-tools.asciidoc
@@ -4,13 +4,29 @@
 
 [partintro]
 --
-The *Dev Tools* page contains development tools that you can use to interact
-with your data in Kibana.
+*Dev Tools* contains tools that you can use to interact
+with your data.
 
-* <<console-kibana, Console>>
-* <<xpack-profiler, Search Profiler>>
-* <<xpack-grokdebugger, Grok Debugger>>
+[cols="2"]
+|===
 
+a| <<console-kibana, Console>>
+
+| Interact with the REST API of Elasticsearch, including sending requests
+and viewing API documentation.
+
+a| <<xpack-profiler, Search&nbsp;Profiler>>
+
+| Inspect and analyze your search queries.
+
+a| <<xpack-grokdebugger, Grok&nbsp;Debugger&nbsp;&nbsp;&nbsp;>>
+
+| Build and debug grok patterns before you use them in your data processing pipelines.
+
+a| <<painlesslab, Painless&nbsp;Lab>>
+
+| beta:[] Test and debug Painless scripts in real-time.
+|===
 
 --
 
@@ -19,3 +35,5 @@ include::{kib-repo-dir}/dev-tools/console/console.asciidoc[]
 include::{kib-repo-dir}/dev-tools/searchprofiler/index.asciidoc[]
 
 include::{kib-repo-dir}/dev-tools/grokdebugger/index.asciidoc[]
+
+include::{kib-repo-dir}/dev-tools/painlesslab/index.asciidoc[]

From 087df824523d007409c68e7d3ba32d824cce07ee Mon Sep 17 00:00:00 2001
From: Chris Cowan <chris@chriscowan.us>
Date: Thu, 9 Apr 2020 11:48:56 -0700
Subject: [PATCH 35/78] [TSVB] Add Positive Rate to Aggregations (#59843)

* [TSVB] Add Rate to Aggregations

* Fixing i18n labels

* Changing from rate to growth_rate; adding message to aggregation form;

* Change units to scale; change free text to combobox

* Fixing placeholder

* Fixing i18n label

* Changing from Growth Rate to Positive Rate

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../public/components/aggs/agg_select.js      |   6 +
 .../public/components/aggs/positive_rate.js   | 191 ++++++++++++++++++
 .../public/components/lib/agg_to_component.js |   2 +
 .../vis_type_timeseries/common/agg_lookup.js  |   3 +
 .../common/calculate_label.js                 |   6 +
 .../request_processors/series/index.js        |   2 +
 .../series/positive_rate.js                   |  68 +++++++
 .../series/positive_rate.test.js              |  95 +++++++++
 .../request_processors/table/index.js         |   2 +
 .../request_processors/table/positive_rate.js |  35 ++++
 10 files changed, 410 insertions(+)
 create mode 100644 src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/positive_rate.js
 create mode 100644 src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js
 create mode 100644 src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js
 create mode 100644 src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.js

diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/agg_select.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/agg_select.js
index f93dee14d0eed..8607ff184dfaa 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/agg_select.js
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/agg_select.js
@@ -49,6 +49,12 @@ const metricAggs = [
     }),
     value: 'filter_ratio',
   },
+  {
+    label: i18n.translate('visTypeTimeseries.aggSelect.metricsAggs.positiveRateLabel', {
+      defaultMessage: 'Positive Rate',
+    }),
+    value: 'positive_rate',
+  },
   {
     label: i18n.translate('visTypeTimeseries.aggSelect.metricsAggs.maxLabel', {
       defaultMessage: 'Max',
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/positive_rate.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/positive_rate.js
new file mode 100644
index 0000000000000..39558fa3a9224
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/positive_rate.js
@@ -0,0 +1,191 @@
+/*
+ * 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 PropTypes from 'prop-types';
+import React from 'react';
+import { AggSelect } from './agg_select';
+import { FieldSelect } from './field_select';
+import { AggRow } from './agg_row';
+import { createChangeHandler } from '../lib/create_change_handler';
+import { createSelectHandler } from '../lib/create_select_handler';
+import {
+  htmlIdGenerator,
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiFormLabel,
+  EuiFormRow,
+  EuiSpacer,
+  EuiText,
+  EuiLink,
+  EuiComboBox,
+} from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { i18n } from '@kbn/i18n';
+import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public';
+
+const UNIT_OPTIONS = [
+  {
+    label: i18n.translate('visTypeTimeseries.units.auto', { defaultMessage: 'auto' }),
+    value: '',
+  },
+  {
+    label: i18n.translate('visTypeTimeseries.units.perMillisecond', {
+      defaultMessage: 'per millisecond',
+    }),
+    value: '1ms',
+  },
+  {
+    label: i18n.translate('visTypeTimeseries.units.perSecond', { defaultMessage: 'per second' }),
+    value: '1s',
+  },
+  {
+    label: i18n.translate('visTypeTimeseries.units.perMinute', { defaultMessage: 'per minute' }),
+    value: '1m',
+  },
+  {
+    label: i18n.translate('visTypeTimeseries.units.perHour', { defaultMessage: 'per hour' }),
+    value: '1h',
+  },
+  {
+    label: i18n.translate('visTypeTimeseries.units.perDay', { defaultMessage: 'per day' }),
+    value: '1d',
+  },
+];
+
+export const PositiveRateAgg = props => {
+  const defaults = { unit: '' };
+  const model = { ...defaults, ...props.model };
+
+  const handleChange = createChangeHandler(props.onChange, model);
+  const handleSelectChange = createSelectHandler(handleChange);
+
+  const htmlId = htmlIdGenerator();
+  const indexPattern =
+    (props.series.override_index_pattern && props.series.series_index_pattern) ||
+    props.panel.index_pattern;
+
+  const selectedUnitOptions = UNIT_OPTIONS.filter(o => o.value === model.unit);
+
+  return (
+    <AggRow
+      disableDelete={props.disableDelete}
+      model={props.model}
+      onAdd={props.onAdd}
+      onDelete={props.onDelete}
+      siblings={props.siblings}
+      dragHandleProps={props.dragHandleProps}
+    >
+      <EuiFlexGroup gutterSize="s">
+        <EuiFlexItem>
+          <EuiFormLabel htmlFor={htmlId('aggregation')}>
+            <FormattedMessage
+              id="visTypeTimeseries.positiveRate.aggregationLabel"
+              defaultMessage="Aggregation"
+            />
+          </EuiFormLabel>
+          <EuiSpacer size="xs" />
+          <AggSelect
+            id={htmlId('aggregation')}
+            panelType={props.panel.type}
+            siblings={props.siblings}
+            value={model.type}
+            onChange={handleSelectChange('type')}
+            fullWidth
+          />
+        </EuiFlexItem>
+        <EuiFlexItem>
+          <EuiFormRow
+            id={htmlId('field')}
+            label={
+              <FormattedMessage
+                id="visTypeTimeseries.postiveRate.fieldLabel"
+                defaultMessage="Field"
+              />
+            }
+            fullWidth
+          >
+            <FieldSelect
+              fields={props.fields}
+              type={model.type}
+              restrict={KBN_FIELD_TYPES.NUMBER}
+              indexPattern={indexPattern}
+              value={model.field}
+              onChange={handleSelectChange('field')}
+              uiRestrictions={props.uiRestrictions}
+              fullWidth
+            />
+          </EuiFormRow>
+        </EuiFlexItem>
+        <EuiFlexItem>
+          <EuiFormRow
+            id={htmlId('units')}
+            label={
+              <FormattedMessage
+                id="visTypeTimeseries.positiveRate.unitsLabel"
+                defaultMessage="Scale"
+              />
+            }
+            fullWidth
+          >
+            <EuiComboBox
+              placeholder={i18n.translate('visTypeTimeseries.positiveRate.unitSelectPlaceholder', {
+                defaultMessage: 'Select scale...',
+              })}
+              options={UNIT_OPTIONS}
+              onChange={handleSelectChange('unit')}
+              singleSelection={{ asPlainText: true }}
+              selectedOptions={selectedUnitOptions}
+            />
+          </EuiFormRow>
+        </EuiFlexItem>
+      </EuiFlexGroup>
+      <EuiSpacer size="s" />
+      <EuiText size="xs" color="subdued">
+        <p>
+          <FormattedMessage
+            id="visTypeTimeseries.positiveRate.helpText"
+            defaultMessage="This aggregation should only be applied to {link}, it is a shortcut for applying max, derivative and positive only to a field."
+            values={{
+              link: (
+                <EuiLink href="https://en.wikipedia.org/wiki/Monotonic_function" target="_BLANK">
+                  <FormattedMessage
+                    id="visTypeTimeseries.positiveRate.helpTextLink"
+                    defaultMessage="monotonically increasing numbers"
+                  />
+                </EuiLink>
+              ),
+            }}
+          />
+        </p>
+      </EuiText>
+    </AggRow>
+  );
+};
+
+PositiveRateAgg.propTypes = {
+  disableDelete: PropTypes.bool,
+  fields: PropTypes.object,
+  model: PropTypes.object,
+  onAdd: PropTypes.func,
+  onChange: PropTypes.func,
+  onDelete: PropTypes.func,
+  panel: PropTypes.object,
+  series: PropTypes.object,
+  siblings: PropTypes.array,
+};
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/agg_to_component.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/agg_to_component.js
index ca40d60f20848..a53192afafdcc 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/agg_to_component.js
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/agg_to_component.js
@@ -33,6 +33,7 @@ import { PercentileRankAgg } from '../aggs/percentile_rank';
 import { Static } from '../aggs/static';
 import { MathAgg } from '../aggs/math';
 import { TopHitAgg } from '../aggs/top_hit';
+import { PositiveRateAgg } from '../aggs/positive_rate';
 
 export const aggToComponent = {
   count: StandardAgg,
@@ -65,4 +66,5 @@ export const aggToComponent = {
   static: Static,
   math: MathAgg,
   top_hit: TopHitAgg,
+  positive_rate: PositiveRateAgg,
 };
diff --git a/src/plugins/vis_type_timeseries/common/agg_lookup.js b/src/plugins/vis_type_timeseries/common/agg_lookup.js
index 4dfdc83dcfabb..432da03e3d45d 100644
--- a/src/plugins/vis_type_timeseries/common/agg_lookup.js
+++ b/src/plugins/vis_type_timeseries/common/agg_lookup.js
@@ -97,6 +97,9 @@ export const lookup = {
     defaultMessage: 'Static Value',
   }),
   top_hit: i18n.translate('visTypeTimeseries.aggLookup.topHitLabel', { defaultMessage: 'Top Hit' }),
+  positive_rate: i18n.translate('visTypeTimeseries.aggLookup.positiveRateLabel', {
+    defaultMessage: 'Positive Rate',
+  }),
 };
 
 const pipeline = [
diff --git a/src/plugins/vis_type_timeseries/common/calculate_label.js b/src/plugins/vis_type_timeseries/common/calculate_label.js
index 756d6e57a83e8..71aa0aed7dc11 100644
--- a/src/plugins/vis_type_timeseries/common/calculate_label.js
+++ b/src/plugins/vis_type_timeseries/common/calculate_label.js
@@ -70,6 +70,12 @@ export function calculateLabel(metric, metrics) {
       defaultMessage: 'Filter Ratio',
     });
   }
+  if (metric.type === 'positive_rate') {
+    return i18n.translate('visTypeTimeseries.calculateLabel.positiveRateLabel', {
+      defaultMessage: 'Positive Rate of {field}',
+      values: { field: metric.field },
+    });
+  }
   if (metric.type === 'static') {
     return i18n.translate('visTypeTimeseries.calculateLabel.staticValueLabel', {
       defaultMessage: 'Static Value of {metricValue}',
diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js
index 4b0b8f33716a2..c727a3131f5df 100644
--- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js
+++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js
@@ -26,6 +26,7 @@ import { dateHistogram } from './date_histogram';
 import { metricBuckets } from './metric_buckets';
 import { siblingBuckets } from './sibling_buckets';
 import { ratios as filterRatios } from './filter_ratios';
+import { positiveRate } from './positive_rate';
 import { normalizeQuery } from './normalize_query';
 
 export const processors = [
@@ -38,5 +39,6 @@ export const processors = [
   metricBuckets,
   siblingBuckets,
   filterRatios,
+  positiveRate,
   normalizeQuery,
 ];
diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js
new file mode 100644
index 0000000000000..1ff548cc19e02
--- /dev/null
+++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js
@@ -0,0 +1,68 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { getBucketSize } from '../../helpers/get_bucket_size';
+import { getIntervalAndTimefield } from '../../get_interval_and_timefield';
+import { bucketTransform } from '../../helpers/bucket_transform';
+import { set } from 'lodash';
+
+export const filter = metric => metric.type === 'positive_rate';
+
+export const createPositiveRate = (doc, intervalString, aggRoot) => metric => {
+  const maxFn = bucketTransform.max;
+  const derivativeFn = bucketTransform.derivative;
+  const positiveOnlyFn = bucketTransform.positive_only;
+
+  const maxMetric = { id: `${metric.id}-positive-rate-max`, type: 'max', field: metric.field };
+  const derivativeMetric = {
+    id: `${metric.id}-positive-rate-derivative`,
+    type: 'derivative',
+    field: `${metric.id}-positive-rate-max`,
+    unit: metric.unit,
+  };
+  const positiveOnlyMetric = {
+    id: metric.id,
+    type: 'positive_only',
+    field: `${metric.id}-positive-rate-derivative`,
+  };
+
+  const fakeSeriesMetrics = [maxMetric, derivativeMetric, positiveOnlyMetric];
+
+  const maxBucket = maxFn(maxMetric, fakeSeriesMetrics, intervalString);
+  const derivativeBucket = derivativeFn(derivativeMetric, fakeSeriesMetrics, intervalString);
+  const positiveOnlyBucket = positiveOnlyFn(positiveOnlyMetric, fakeSeriesMetrics, intervalString);
+
+  set(doc, `${aggRoot}.timeseries.aggs.${metric.id}-positive-rate-max`, maxBucket);
+  set(doc, `${aggRoot}.timeseries.aggs.${metric.id}-positive-rate-derivative`, derivativeBucket);
+  set(doc, `${aggRoot}.timeseries.aggs.${metric.id}`, positiveOnlyBucket);
+};
+
+export function positiveRate(req, panel, series, esQueryConfig, indexPatternObject, capabilities) {
+  return next => doc => {
+    const { interval } = getIntervalAndTimefield(panel, series, indexPatternObject);
+    const { intervalString } = getBucketSize(req, interval, capabilities);
+    if (series.metrics.some(filter)) {
+      series.metrics
+        .filter(filter)
+        .forEach(createPositiveRate(doc, intervalString, `aggs.${series.id}.aggs`));
+      return next(doc);
+    }
+    return next(doc);
+  };
+}
diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js
new file mode 100644
index 0000000000000..946884c05c722
--- /dev/null
+++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js
@@ -0,0 +1,95 @@
+/*
+ * 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 { positiveRate } from './positive_rate';
+describe('positiveRate(req, panel, series)', () => {
+  let panel;
+  let series;
+  let req;
+  beforeEach(() => {
+    panel = {
+      time_field: 'timestamp',
+    };
+    series = {
+      id: 'test',
+      split_mode: 'terms',
+      terms_size: 10,
+      terms_field: 'host',
+      metrics: [
+        {
+          id: 'metric-1',
+          type: 'positive_rate',
+          field: 'system.network.out.bytes',
+          unit: '1s',
+        },
+      ],
+    };
+    req = {
+      payload: {
+        timerange: {
+          min: '2017-01-01T00:00:00Z',
+          max: '2017-01-01T01:00:00Z',
+        },
+      },
+    };
+  });
+
+  test('calls next when finished', () => {
+    const next = jest.fn();
+    positiveRate(req, panel, series)(next)({});
+    expect(next.mock.calls.length).toEqual(1);
+  });
+
+  test('returns positive rate aggs', () => {
+    const next = doc => doc;
+    const doc = positiveRate(req, panel, series)(next)({});
+    expect(doc).toEqual({
+      aggs: {
+        test: {
+          aggs: {
+            timeseries: {
+              aggs: {
+                'metric-1-positive-rate-max': {
+                  max: { field: 'system.network.out.bytes' },
+                },
+                'metric-1-positive-rate-derivative': {
+                  derivative: {
+                    buckets_path: 'metric-1-positive-rate-max',
+                    gap_policy: 'skip',
+                    unit: '1s',
+                  },
+                },
+                'metric-1': {
+                  bucket_script: {
+                    buckets_path: { value: 'metric-1-positive-rate-derivative[normalized_value]' },
+                    script: {
+                      source: 'params.value > 0.0 ? params.value : 0.0',
+                      lang: 'painless',
+                    },
+                    gap_policy: 'skip',
+                  },
+                },
+              },
+            },
+          },
+        },
+      },
+    });
+  });
+});
diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js
index a62533ae7a37c..5864d2538005d 100644
--- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js
+++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js
@@ -26,6 +26,7 @@ import { metricBuckets } from './metric_buckets';
 import { siblingBuckets } from './sibling_buckets';
 import { ratios as filterRatios } from './filter_ratios';
 import { normalizeQuery } from './normalize_query';
+import { positiveRate } from './positive_rate';
 
 export const processors = [
   query,
@@ -36,5 +37,6 @@ export const processors = [
   metricBuckets,
   siblingBuckets,
   filterRatios,
+  positiveRate,
   normalizeQuery,
 ];
diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.js
new file mode 100644
index 0000000000000..da4b834822d70
--- /dev/null
+++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.js
@@ -0,0 +1,35 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { getBucketSize } from '../../helpers/get_bucket_size';
+import { getIntervalAndTimefield } from '../../get_interval_and_timefield';
+import { calculateAggRoot } from './calculate_agg_root';
+import { createPositiveRate, filter } from '../series/positive_rate';
+
+export function positiveRate(req, panel, esQueryConfig, indexPatternObject) {
+  return next => doc => {
+    const { interval } = getIntervalAndTimefield(panel, {}, indexPatternObject);
+    const { intervalString } = getBucketSize(req, interval);
+    panel.series.forEach(column => {
+      const aggRoot = calculateAggRoot(doc, column);
+      column.metrics.filter(filter).forEach(createPositiveRate(doc, intervalString, aggRoot));
+    });
+    return next(doc);
+  };
+}

From b8738b0eebf7a7ad708b5f498dcc51f6a7fb2c87 Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Thu, 9 Apr 2020 15:05:09 -0400
Subject: [PATCH 36/78] Ensure that discover data exists for home/_navigation
 test so that the test suite can run in isolation (#62516)

---
 test/functional/apps/home/_navigation.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/functional/apps/home/_navigation.ts b/test/functional/apps/home/_navigation.ts
index efc0dad394464..2c927e9a2f4c7 100644
--- a/test/functional/apps/home/_navigation.ts
+++ b/test/functional/apps/home/_navigation.ts
@@ -52,6 +52,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
 
   describe('Kibana browser back navigation should work', function describeIndexTests() {
     before(async () => {
+      await esArchiver.loadIfNeeded('discover');
       await esArchiver.loadIfNeeded('logstash_functional');
       if (browser.isInternetExplorer) {
         await kibanaServer.uiSettings.replace({ 'state:storeInSessionStorage': false });

From e61680571acce5b6bb8be8d9f6e574864c49f290 Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Thu, 9 Apr 2020 15:05:21 -0400
Subject: [PATCH 37/78] Ensure alerting action exists in connectors test setup
 (#62511)

---
 .../apps/triggers_actions_ui/connectors.ts                | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts
index c2013ba3502e2..b5bcd33c3b9ab 100644
--- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts
+++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts
@@ -13,12 +13,20 @@ function generateUniqueKey() {
 }
 
 export default ({ getPageObjects, getService }: FtrProviderContext) => {
+  const alerting = getService('alerting');
   const testSubjects = getService('testSubjects');
   const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']);
   const find = getService('find');
 
   describe('Connectors', function() {
     before(async () => {
+      await alerting.actions.createAction({
+        name: `server-log-${Date.now()}`,
+        actionTypeId: '.server-log',
+        config: {},
+        secrets: {},
+      });
+
       await pageObjects.common.navigateToApp('triggersActions');
       await testSubjects.click('connectorsTab');
     });

From 783e3c17a9ed32d6a5aff39a83bdfa38aa152bf1 Mon Sep 17 00:00:00 2001
From: Tim Schnell <timductive@gmail.com>
Date: Thu, 9 Apr 2020 14:32:24 -0500
Subject: [PATCH 38/78] ignore some things for code coverage (#62701)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 x-pack/legacy/plugins/canvas/scripts/jest.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/x-pack/legacy/plugins/canvas/scripts/jest.js b/x-pack/legacy/plugins/canvas/scripts/jest.js
index cce1b8d355846..133f775c7192f 100644
--- a/x-pack/legacy/plugins/canvas/scripts/jest.js
+++ b/x-pack/legacy/plugins/canvas/scripts/jest.js
@@ -36,6 +36,14 @@ run(
         `!${path}/**/__tests__/**/*`,
         '--collectCoverageFrom', // Ignore coverage on example files
         `!${path}/**/__examples__/**/*`,
+        '--collectCoverageFrom', // Ignore flot files
+        `!${path}/**/flot-charts/**`,
+        '--collectCoverageFrom', // Ignore coverage files
+        `!${path}/**/coverage/**`,
+        '--collectCoverageFrom', // Ignore scripts
+        `!${path}/**/scripts/**`,
+        '--collectCoverageFrom', // Ignore mock files
+        `!${path}/**/mocks/**`,
         '--collectCoverageFrom', // Include JS files
         `${path}/**/*.js`,
         '--collectCoverageFrom', // Include TS/X files
@@ -76,7 +84,7 @@ run(
         --all              Runs all tests and snapshots.  Slower.
         --storybook        Runs Storybook Snapshot tests only.
         --update           Updates Storybook Snapshot tests.
-        --path <string>    Runs any tests at a given path. 
+        --path <string>    Runs any tests at a given path.
         --coverage         Collect coverage statistics.
       `,
     },

From 834306458ac5178cbe26a0f962c764a0451568e2 Mon Sep 17 00:00:00 2001
From: Frank Hassanabad <frank.hassanabad@elastic.co>
Date: Thu, 9 Apr 2020 13:52:02 -0600
Subject: [PATCH 39/78] Fixes a needed import that was coming from APM but now
 isolates things better for optimization import builds

## Summary

Adds a single line to work with ts config optimizers. What is happening is that this is relying on an import from here:

```
x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx
```

when really it should be isolated and imported within this file.

Testing is just to go to siem and run these commands:

```ts
cd /projects/kibana
node x-pack/legacy/plugins/siem/scripts/optimize_tsconfig.js
node scripts/type_check.js --project x-pack/tsconfig.json
```

Ensure you don't see any errors.
---
 .../public/application/components/health_check.test.tsx          | 1 +
 1 file changed, 1 insertion(+)

diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
index 5156a6146f3a1..9c51139993b3f 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
@@ -10,6 +10,7 @@ import { HealthCheck } from './health_check';
 
 import { act } from 'react-dom/test-utils';
 import { httpServiceMock } from '../../../../../../src/core/public/mocks';
+import '@testing-library/jest-dom/extend-expect';
 
 const docLinks = { ELASTIC_WEBSITE_URL: 'elastic.co/', DOC_LINK_VERSION: 'current' };
 

From bc8c4a754db653762fe50a7bfc9bee7f9006e20c Mon Sep 17 00:00:00 2001
From: Aaron Caldwell <aaron.caldwell@elastic.co>
Date: Thu, 9 Apr 2020 15:43:07 -0600
Subject: [PATCH 40/78] [File upload] Change 'file_upload' id and refs to
 'fileUpload' (#63000)

---
 x-pack/plugins/file_upload/kibana.json | 3 +--
 x-pack/plugins/maps/public/plugin.ts   | 4 ++--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/x-pack/plugins/file_upload/kibana.json b/x-pack/plugins/file_upload/kibana.json
index 3fda32fb6ebe5..7676a01d0b0f9 100644
--- a/x-pack/plugins/file_upload/kibana.json
+++ b/x-pack/plugins/file_upload/kibana.json
@@ -1,8 +1,7 @@
 {
-  "id": "file_upload",
+  "id": "fileUpload",
   "version": "8.0.0",
   "kibanaVersion": "kibana",
-  "configPath": ["xpack", "file_upload"],
   "server": true,
   "ui": true,
   "requiredPlugins": ["data", "usageCollection"]
diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts
index 9437c2512ded4..14487b615e759 100644
--- a/x-pack/plugins/maps/public/plugin.ts
+++ b/x-pack/plugins/maps/public/plugin.ts
@@ -43,9 +43,9 @@ export const bindSetupCoreAndPlugins = (core: CoreSetup, plugins: any) => {
 };
 
 export const bindStartCoreAndPlugins = (core: CoreStart, plugins: any) => {
-  const { file_upload, data, inspector } = plugins;
+  const { fileUpload, data, inspector } = plugins;
   setInspector(inspector);
-  setFileUpload(file_upload);
+  setFileUpload(fileUpload);
   setIndexPatternSelect(data.ui.IndexPatternSelect);
   setTimeFilter(data.query.timefilter.timefilter);
   setIndexPatternService(data.indexPatterns);

From 93b34632c08884e7850114f1fe21adfb47471c22 Mon Sep 17 00:00:00 2001
From: Marco Vettorello <vettorello.marco@gmail.com>
Date: Thu, 9 Apr 2020 23:53:47 +0200
Subject: [PATCH 41/78] [TSVB] Fix wrongly display stacked as percentage charts
 (#62654)

Update to  elastic-charts 18.2.2 with the valid 0% rendering
---
 package.json                             | 2 +-
 packages/kbn-ui-shared-deps/package.json | 2 +-
 yarn.lock                                | 8 ++++----
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/package.json b/package.json
index bd0fec3a5c116..ea930d07e7b43 100644
--- a/package.json
+++ b/package.json
@@ -119,7 +119,7 @@
     "@babel/core": "^7.9.0",
     "@babel/register": "^7.9.0",
     "@elastic/apm-rum": "^4.6.0",
-    "@elastic/charts": "^18.1.1",
+    "@elastic/charts": "18.2.2",
     "@elastic/datemath": "5.0.3",
     "@elastic/ems-client": "7.8.0",
     "@elastic/eui": "21.0.1",
diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json
index e2823f23d0431..7c5d6a62a11ca 100644
--- a/packages/kbn-ui-shared-deps/package.json
+++ b/packages/kbn-ui-shared-deps/package.json
@@ -9,7 +9,7 @@
     "kbn:watch": "node scripts/build --watch"
   },
   "dependencies": {
-    "@elastic/charts": "^18.1.1",
+    "@elastic/charts": "18.2.2",
     "@elastic/eui": "21.0.1",
     "@kbn/i18n": "1.0.0",
     "abortcontroller-polyfill": "^1.4.0",
diff --git a/yarn.lock b/yarn.lock
index 3f04b2d26a013..20e33fdefc996 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1197,10 +1197,10 @@
   dependencies:
     "@elastic/apm-rum-core" "^4.7.0"
 
-"@elastic/charts@^18.1.1":
-  version "18.2.0"
-  resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-18.2.0.tgz#e141151b4d7ecc71c9f6f235f8ce141665c67195"
-  integrity sha512-OWsARaHI/4Ict/GkeKIO3a+e2c86esGw3FtSGRLPFVgzpwBXdjvjYyraGntKOIVs/NAGNVWYj5XoRRb5C6cMlQ==
+"@elastic/charts@18.2.2":
+  version "18.2.2"
+  resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-18.2.2.tgz#f59d6ee597d553d193314d8598561c65da787e8d"
+  integrity sha512-ss8AqLj9wHa2C+9ULUKbXw8ZCQmEjLuaVU5AkqE2j3hOVtAN75HO2p7nMIsxcSldfmqy+4jSptybJLNAfizegQ==
   dependencies:
     classnames "^2.2.6"
     d3-array "^1.2.4"

From 982c0da78e67694e0c2e05e8e2e7431ab9bda880 Mon Sep 17 00:00:00 2001
From: CJ Cenizal <cj@cenizal.com>
Date: Thu, 9 Apr 2020 16:51:22 -0700
Subject: [PATCH 42/78] Move ILM out of legacy (#61915)

* Rename IndexMgmtSetup to IndexManagementPluginSetup.
* Remove unused fetch index template route and related tests.
* Remove unnecessary custom styles.
---
 .github/CODEOWNERS                            |   2 +-
 x-pack/.i18nrc.json                           |   2 +-
 x-pack/index.js                               |   2 -
 .../np_ready/extend_index_management.ts       |   4 +-
 .../public/np_ready/plugin.ts                 |   4 +-
 .../server/np_ready/plugin.ts                 |   4 +-
 .../index_lifecycle_management/index.ts       |  62 --------
 .../index_lifecycle_management/plugin.ts      |  54 -------
 .../public/legacy.ts                          | 109 -------------
 .../_index_lifecycle_management.scss          |  17 --
 .../public/np_ready/application/index.scss    |   3 -
 .../public/np_ready/application/index.tsx     |  63 --------
 .../np_ready/application/services/api.js      |  81 ----------
 .../public/np_ready/plugin.tsx                |  58 -------
 .../call_with_request_factory.ts              |  19 ---
 .../lib/call_with_request_factory/index.ts    |   7 -
 .../check_license/__tests__/check_license.js  | 145 ------------------
 .../server/lib/check_license/check_license.ts |  66 --------
 .../__tests__/wrap_custom_error.js            |  21 ---
 .../error_wrappers/__tests__/wrap_es_error.js |  38 -----
 .../__tests__/wrap_unknown_error.js           |  19 ---
 .../server/lib/error_wrappers/index.ts        |   9 --
 .../lib/error_wrappers/wrap_custom_error.ts   |  18 ---
 .../lib/error_wrappers/wrap_es_error.ts       |  29 ----
 .../lib/error_wrappers/wrap_unknown_error.ts  |  17 --
 .../server/lib/is_es_error/index.ts           |   7 -
 .../__tests__/license_pre_routing_factory.js  |  69 ---------
 .../license_pre_routing_factory.ts            |  29 ----
 .../lib/register_license_checker/index.ts     |   7 -
 .../register_license_checker.ts               |  23 ---
 .../server/routes/api/index/index.ts          |   7 -
 .../api/index/register_add_policy_route.ts    |  58 -------
 .../routes/api/index/register_remove_route.ts |  51 ------
 .../routes/api/index/register_retry_route.ts  |  51 ------
 .../server/routes/api/nodes/constants.ts      |  15 --
 .../server/routes/api/nodes/index.ts          |   7 -
 .../api/nodes/register_details_route.ts       |  61 --------
 .../routes/api/nodes/register_list_route.ts   |  63 --------
 .../server/routes/api/policies/index.ts       |   7 -
 .../api/policies/register_create_route.ts     |  52 -------
 .../api/policies/register_delete_route.ts     |  46 ------
 .../api/policies/register_fetch_route.ts      |  84 ----------
 .../server/routes/api/templates/index.ts      |   7 -
 .../templates/register_add_policy_route.ts    |  67 --------
 .../api/templates/register_get_route.ts       |  48 ------
 .../index_lifecycle_management/shim.ts        |  17 --
 .../legacy/plugins/index_management/index.ts  |   1 +
 x-pack/legacy/plugins/rollup/public/plugin.ts |   4 +-
 x-pack/legacy/plugins/rollup/server/plugin.ts |   4 +-
 .../extend_index_management.test.js.snap      |   0
 .../__snapshots__/policy_table.test.js.snap   |   0
 .../__jest__/components/edit_policy.test.js   |  20 ++-
 .../__jest__/components/policy_table.test.js  |  16 +-
 .../__jest__/extend_index_management.test.js  |  17 +-
 .../common/constants/index.ts                 |   6 +
 .../index_lifecycle_management/kibana.json    |  16 ++
 .../public}/application/app.tsx               |   2 +-
 .../public}/application/constants/index.ts    |   0
 .../application/constants/ui_metric.ts        |   0
 .../public/application/index.tsx              |  27 ++++
 .../sections/components/active_badge.js       |   0
 .../application/sections/components/index.js  |   0
 .../sections/components/learn_more_link.js    |   0
 .../sections/components/optional_label.js     |   0
 .../components/phase_error_message.js         |   0
 .../cold_phase/cold_phase.container.js        |   0
 .../components/cold_phase/cold_phase.js       |   0
 .../components/cold_phase/index.js            |   0
 .../delete_phase/delete_phase.container.js    |   0
 .../components/delete_phase/delete_phase.js   |   0
 .../components/delete_phase/index.js          |   0
 .../hot_phase/hot_phase.container.js          |   0
 .../components/hot_phase/hot_phase.js         |   0
 .../edit_policy/components/hot_phase/index.js |   0
 .../edit_policy/components/min_age_input.js   |   0
 .../components/node_allocation/index.js       |   0
 .../node_allocation.container.js              |   0
 .../node_allocation/node_allocation.js        |   0
 .../components/node_attrs_details/index.js    |   0
 .../node_attrs_details.container.js           |   0
 .../node_attrs_details/node_attrs_details.js  |   0
 .../components/policy_json_flyout.js          |   0
 .../components/set_priority_input.js          |   0
 .../components/warm_phase/index.js            |   0
 .../warm_phase/warm_phase.container.js        |   0
 .../components/warm_phase/warm_phase.js       |   0
 .../edit_policy/edit_policy.container.js      |   0
 .../sections/edit_policy/edit_policy.js       |   0
 .../sections/edit_policy/form_errors.js       |   0
 .../sections/edit_policy/index.d.ts           |   0
 .../application/sections/edit_policy/index.js |   0
 .../no_match/components/no_match/index.js     |   0
 .../no_match/components/no_match/no_match.js  |   0
 .../policy_table/components/no_match/index.js |   0
 .../add_policy_to_template_confirm_modal.js   |   0
 .../components/policy_table/confirm_delete.js |   0
 .../components/policy_table/index.js          |   0
 .../policy_table/policy_table.container.js    |   0
 .../components/policy_table/policy_table.js   |   8 +-
 .../sections/policy_table/index.d.ts          |   0
 .../sections/policy_table/index.js            |   0
 .../public/application/services/api.js        |  72 +++++++++
 .../application/services/api_errors.js        |   0
 .../application/services/documentation.ts     |   0
 .../application/services/filter_items.js      |   0
 .../application/services/find_errors.js       |   0
 .../services/flatten_panel_tree.js            |   0
 .../public}/application/services/http.ts      |  14 +-
 .../public}/application/services/index.js     |   0
 .../application/services/navigation.ts        |  12 +-
 .../application/services/notification.ts      |   0
 .../application/services/sort_table.js        |   0
 .../application/services/ui_metric.test.js    |   0
 .../public}/application/services/ui_metric.ts |  11 +-
 .../application/store/actions/general.js      |   0
 .../application/store/actions/index.js        |   0
 .../application/store/actions/lifecycle.js    |   0
 .../application/store/actions/nodes.js        |   0
 .../application/store/actions/policies.js     |   0
 .../application/store/defaults/cold_phase.js  |   0
 .../store/defaults/delete_phase.js            |   0
 .../application/store/defaults/hot_phase.js   |   0
 .../application/store/defaults/index.d.ts     |   0
 .../application/store/defaults/index.js       |   0
 .../application/store/defaults/warm_phase.js  |   0
 .../public}/application/store/index.d.ts      |   0
 .../public}/application/store/index.js        |   0
 .../application/store/reducers/general.js     |   0
 .../application/store/reducers/index.js       |   0
 .../application/store/reducers/nodes.js       |   0
 .../application/store/reducers/policies.js    |   0
 .../application/store/selectors/general.js    |   0
 .../application/store/selectors/index.js      |   0
 .../application/store/selectors/lifecycle.js  |   0
 .../application/store/selectors/nodes.js      |   0
 .../application/store/selectors/policies.js   |   0
 .../public}/application/store/store.js        |   0
 .../components/add_lifecycle_confirm_modal.js |   6 +-
 .../components/index_lifecycle_summary.js     |   0
 .../remove_lifecycle_confirm_modal.js         |   4 +-
 .../extend_index_management/index.d.ts        |   0
 .../public}/extend_index_management/index.js  |  50 +-----
 .../public}/index.ts                          |   8 +-
 .../public/plugin.tsx                         |  69 +++++++++
 .../public/types.ts                           |  21 +++
 .../server/config.ts                          |  18 +++
 .../server/index.ts                           |  19 +++
 .../server/lib}/is_es_error.ts                |   0
 .../server/plugin.ts                          |  86 +++++++++++
 .../server/routes/api/index/index.ts}         |   9 +-
 .../api/index/register_add_policy_route.ts    |  66 ++++++++
 .../routes/api/index/register_remove_route.ts |  54 +++++++
 .../routes/api/index/register_retry_route.ts  |  54 +++++++
 .../server/routes/api/nodes/index.ts}         |   7 +-
 .../api/nodes/register_details_route.ts       |  64 ++++++++
 .../routes/api/nodes/register_list_route.ts   |  69 +++++++++
 .../server/routes/api/policies/index.ts}      |   9 +-
 .../api/policies/register_create_route.ts     | 145 ++++++++++++++++++
 .../api/policies/register_delete_route.ts     |  50 ++++++
 .../api/policies/register_fetch_route.ts      |  90 +++++++++++
 .../server/routes/api/templates/index.ts}     |   9 +-
 .../templates/register_add_policy_route.ts    |  81 ++++++++++
 .../api/templates/register_fetch_route.ts     |  51 +++---
 .../server/routes/index.ts                    |  19 +++
 .../server/services/add_base_path.ts}         |   4 +-
 .../server/services}/index.ts                 |   3 +-
 .../server/services/license.ts                |  82 ++++++++++
 .../server/types.ts                           |  27 ++++
 .../index_actions_context_menu.js             |  15 +-
 .../plugins/index_management/public/index.ts  |   4 +-
 .../plugins/index_management/public/plugin.ts |   4 +-
 .../plugins/index_management/server/index.ts  |   2 +-
 .../plugins/index_management/server/plugin.ts |   6 +-
 .../translations/translations/ja-JP.json      |   3 -
 .../translations/translations/zh-CN.json      |   3 -
 .../templates.helpers.js                      |   3 -
 .../index_lifecycle_management/templates.js   |  19 +--
 177 files changed, 1264 insertions(+), 1828 deletions(-)
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/plugin.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/_index_lifecycle_management.scss
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.scss
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.tsx
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/api.js
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/plugin.tsx
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/call_with_request_factory.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_custom_error.js
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_es_error.js
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_unknown_error.js
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_custom_error.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_es_error.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/is_es_error/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/register_license_checker.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/constants.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/index.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_get_route.ts
 delete mode 100644 x-pack/legacy/plugins/index_lifecycle_management/shim.ts
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap (100%)
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/__jest__/components/__snapshots__/policy_table.test.js.snap (100%)
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js (96%)
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js (91%)
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js (93%)
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/common/constants/index.ts (72%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/kibana.json
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/app.tsx (94%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/constants/index.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/constants/ui_metric.ts (100%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/index.tsx
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/components/active_badge.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/components/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/components/learn_more_link.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/components/optional_label.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/components/phase_error_message.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/cold_phase/cold_phase.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/cold_phase/cold_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/cold_phase/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/delete_phase/delete_phase.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/delete_phase/delete_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/delete_phase/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/hot_phase/hot_phase.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/hot_phase/hot_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/hot_phase/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/min_age_input.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/node_allocation/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/node_allocation/node_allocation.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/node_allocation/node_allocation.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/node_attrs_details/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/policy_json_flyout.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/set_priority_input.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/warm_phase/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/warm_phase/warm_phase.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/components/warm_phase/warm_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/edit_policy.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/edit_policy.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/form_errors.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/index.d.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/edit_policy/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/no_match/components/no_match/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/no_match/components/no_match/no_match.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/no_match/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/policy_table/add_policy_to_template_confirm_modal.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/policy_table/confirm_delete.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/policy_table/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/policy_table/policy_table.container.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/components/policy_table/policy_table.js (98%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/index.d.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/sections/policy_table/index.js (100%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/services/api.js
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/api_errors.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/documentation.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/filter_items.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/find_errors.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/flatten_panel_tree.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/http.ts (50%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/navigation.ts (59%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/notification.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/sort_table.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/ui_metric.test.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/services/ui_metric.ts (85%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/actions/general.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/actions/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/actions/lifecycle.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/actions/nodes.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/actions/policies.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/defaults/cold_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/defaults/delete_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/defaults/hot_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/defaults/index.d.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/defaults/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/defaults/warm_phase.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/index.d.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/reducers/general.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/reducers/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/reducers/nodes.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/reducers/policies.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/selectors/general.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/selectors/index.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/selectors/lifecycle.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/selectors/nodes.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/selectors/policies.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/application/store/store.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/extend_index_management/components/add_lifecycle_confirm_modal.js (97%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/extend_index_management/components/index_lifecycle_summary.js (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/extend_index_management/components/remove_lifecycle_confirm_modal.js (96%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/extend_index_management/index.d.ts (100%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/extend_index_management/index.js (80%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/public/np_ready => plugins/index_lifecycle_management/public}/index.ts (58%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/public/plugin.tsx
 create mode 100644 x-pack/plugins/index_lifecycle_management/public/types.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/config.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/index.ts
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/lib/is_es_error => plugins/index_lifecycle_management/server/lib}/is_es_error.ts (100%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/plugin.ts
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/routes/api/index/register_index_routes.ts => plugins/index_lifecycle_management/server/routes/api/index/index.ts} (65%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_nodes_routes.ts => plugins/index_lifecycle_management/server/routes/api/nodes/index.ts} (65%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_policies_routes.ts => plugins/index_lifecycle_management/server/routes/api/policies/index.ts} (64%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_templates_routes.ts => plugins/index_lifecycle_management/server/routes/api/templates/index.ts} (64%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts
 rename x-pack/{legacy => }/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts (63%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/routes/index.ts
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/lib/check_license/index.ts => plugins/index_lifecycle_management/server/services/add_base_path.ts} (64%)
 rename x-pack/{legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory => plugins/index_lifecycle_management/server/services}/index.ts (74%)
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/services/license.ts
 create mode 100644 x-pack/plugins/index_lifecycle_management/server/types.ts

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e707250ff3261..267f3dde0b66f 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -180,7 +180,7 @@
 /src/plugins/console/  @elastic/es-ui
 /src/plugins/es_ui_shared/  @elastic/es-ui
 /x-pack/legacy/plugins/cross_cluster_replication/  @elastic/es-ui
-/x-pack/legacy/plugins/index_lifecycle_management/  @elastic/es-ui
+/x-pack/plugins/index_lifecycle_management/  @elastic/es-ui
 /x-pack/legacy/plugins/index_management/  @elastic/es-ui
 /x-pack/legacy/plugins/license_management/  @elastic/es-ui
 /x-pack/legacy/plugins/rollup/  @elastic/es-ui
diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json
index ae8d61769b14c..bbbcc062786b0 100644
--- a/x-pack/.i18nrc.json
+++ b/x-pack/.i18nrc.json
@@ -18,7 +18,7 @@
     "xpack.graph": ["legacy/plugins/graph", "plugins/graph"],
     "xpack.grokDebugger": "plugins/grokdebugger",
     "xpack.idxMgmt": "plugins/index_management",
-    "xpack.indexLifecycleMgmt": "legacy/plugins/index_lifecycle_management",
+    "xpack.indexLifecycleMgmt": "plugins/index_lifecycle_management",
     "xpack.infra": "plugins/infra",
     "xpack.ingestManager": "plugins/ingest_manager",
     "xpack.lens": "legacy/plugins/lens",
diff --git a/x-pack/index.js b/x-pack/index.js
index 6fab13d726fa6..3126dc17a7107 100644
--- a/x-pack/index.js
+++ b/x-pack/index.js
@@ -16,7 +16,6 @@ import { beats } from './legacy/plugins/beats_management';
 import { apm } from './legacy/plugins/apm';
 import { maps } from './legacy/plugins/maps';
 import { indexManagement } from './legacy/plugins/index_management';
-import { indexLifecycleManagement } from './legacy/plugins/index_lifecycle_management';
 import { spaces } from './legacy/plugins/spaces';
 import { canvas } from './legacy/plugins/canvas';
 import { infra } from './legacy/plugins/infra';
@@ -50,7 +49,6 @@ module.exports = function(kibana) {
     maps(kibana),
     canvas(kibana),
     indexManagement(kibana),
-    indexLifecycleManagement(kibana),
     infra(kibana),
     taskManager(kibana),
     rollup(kibana),
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts
index 01c6250383fb8..4ffe0db4e3c4e 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts
@@ -6,7 +6,7 @@
 
 import { i18n } from '@kbn/i18n';
 import { get } from 'lodash';
-import { IndexMgmtSetup } from '../../../../../plugins/index_management/public';
+import { IndexManagementPluginSetup } from '../../../../../plugins/index_management/public';
 
 const propertyPath = 'isFollowerIndex';
 
@@ -21,7 +21,7 @@ const followerBadgeExtension = {
   filterExpression: 'isFollowerIndex:true',
 };
 
-export const extendIndexManagement = (indexManagement?: IndexMgmtSetup) => {
+export const extendIndexManagement = (indexManagement?: IndexManagementPluginSetup) => {
   if (indexManagement) {
     indexManagement.extensionsService.addBadge(followerBadgeExtension);
   }
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts
index f7651cbb210a7..46259c698b282 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts
@@ -11,7 +11,7 @@ import {
   DocLinksStart,
 } from 'src/core/public';
 
-import { IndexMgmtSetup } from '../../../../../plugins/index_management/public';
+import { IndexManagementPluginSetup } from '../../../../../plugins/index_management/public';
 
 // @ts-ignore;
 import { setHttpClient } from './app/services/api';
@@ -21,7 +21,7 @@ import { setNotifications } from './app/services/notifications';
 import { extendIndexManagement } from './extend_index_management';
 
 interface PluginDependencies {
-  indexManagement: IndexMgmtSetup;
+  indexManagement: IndexManagementPluginSetup;
   __LEGACY: {
     chrome: any;
     MANAGEMENT_BREADCRUMB: ChromeBreadcrumb;
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts
index 1012c07af3d2a..829de10ad0177 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts
+++ b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts
@@ -6,7 +6,7 @@
 
 import { Plugin, PluginInitializerContext, CoreSetup } from 'src/core/server';
 
-import { IndexMgmtSetup } from '../../../../../plugins/index_management/server';
+import { IndexManagementPluginSetup } from '../../../../../plugins/index_management/server';
 
 // @ts-ignore
 import { registerLicenseChecker } from './lib/register_license_checker';
@@ -15,7 +15,7 @@ import { registerRoutes } from './routes/register_routes';
 import { ccrDataEnricher } from './cross_cluster_replication_data';
 
 interface PluginDependencies {
-  indexManagement: IndexMgmtSetup;
+  indexManagement: IndexManagementPluginSetup;
   __LEGACY: {
     server: any;
     ccrUIEnabled: boolean;
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/index.ts
deleted file mode 100644
index 9b14b7143bf44..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/index.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { Legacy } from 'kibana';
-import { resolve } from 'path';
-import { PLUGIN } from './common/constants';
-import { Plugin as IndexLifecycleManagementPlugin } from './plugin';
-import { createShim } from './shim';
-
-export function indexLifecycleManagement(kibana: any) {
-  return new kibana.Plugin({
-    id: PLUGIN.ID,
-    configPrefix: 'xpack.ilm',
-    publicDir: resolve(__dirname, 'public'),
-    require: ['kibana', 'elasticsearch', 'xpack_main', 'index_management'],
-    uiExports: {
-      styleSheetPaths: resolve(__dirname, 'public/np_ready/application/index.scss'),
-      managementSections: ['plugins/index_lifecycle_management/legacy'],
-      injectDefaultVars(server: Legacy.Server) {
-        const config = server.config();
-        return {
-          ilmUiEnabled: config.get('xpack.ilm.ui.enabled'),
-        };
-      },
-    },
-    config: (Joi: any) => {
-      return Joi.object({
-        // display menu item
-        ui: Joi.object({
-          enabled: Joi.boolean().default(true),
-        }).default(),
-
-        // enable plugin
-        enabled: Joi.boolean().default(true),
-
-        filteredNodeAttributes: Joi.array()
-          .items(Joi.string())
-          .default([]),
-      }).default();
-    },
-    isEnabled(config: any) {
-      return (
-        config.get('xpack.ilm.enabled') &&
-        config.has('xpack.index_management.enabled') &&
-        config.get('xpack.index_management.enabled')
-      );
-    },
-    init(server: Legacy.Server) {
-      const core = server.newPlatform.setup.core;
-      const plugins = {};
-      const __LEGACY = createShim(server);
-
-      const indexLifecycleManagementPlugin = new IndexLifecycleManagementPlugin();
-
-      // Set up plugin.
-      indexLifecycleManagementPlugin.setup(core, plugins, __LEGACY);
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts b/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts
deleted file mode 100644
index 38d1bea45ce07..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { CoreSetup } from 'kibana/server';
-import { LegacySetup } from './shim';
-import { registerLicenseChecker } from './server/lib/register_license_checker';
-import { registerIndexRoutes } from './server/routes/api/index';
-import { registerNodesRoutes } from './server/routes/api/nodes';
-import { registerPoliciesRoutes } from './server/routes/api/policies';
-import { registerTemplatesRoutes } from './server/routes/api/templates';
-
-const indexLifecycleDataEnricher = async (indicesList: any, callWithRequest: any) => {
-  if (!indicesList || !indicesList.length) {
-    return;
-  }
-  const params = {
-    path: '/*/_ilm/explain',
-    method: 'GET',
-  };
-  const { indices: ilmIndicesData } = await callWithRequest('transport.request', params);
-  return indicesList.map((index: any): any => {
-    return {
-      ...index,
-      ilm: { ...(ilmIndicesData[index.name] || {}) },
-    };
-  });
-};
-
-export class Plugin {
-  public setup(core: CoreSetup, plugins: any, __LEGACY: LegacySetup): void {
-    const { server } = __LEGACY;
-
-    registerLicenseChecker(server);
-
-    // Register routes.
-    registerIndexRoutes(server);
-    registerNodesRoutes(server);
-    registerPoliciesRoutes(server);
-    registerTemplatesRoutes(server);
-
-    const serverPlugins = server.newPlatform.setup.plugins as any;
-
-    if (
-      server.config().get('xpack.ilm.ui.enabled') &&
-      serverPlugins.indexManagement &&
-      serverPlugins.indexManagement.indexDataEnricher
-    ) {
-      serverPlugins.indexManagement.indexDataEnricher.add(indexLifecycleDataEnricher);
-    }
-  }
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts b/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts
deleted file mode 100644
index 006e5f6098f2b..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { App } from 'src/core/public';
-
-/* Legacy Imports */
-import { npSetup, npStart } from 'ui/new_platform';
-import chrome from 'ui/chrome';
-import routes from 'ui/routes';
-import { management } from 'ui/management';
-import { createUiStatsReporter } from '../../../../../src/legacy/core_plugins/ui_metric/public';
-
-import { PLUGIN, BASE_PATH } from '../common/constants';
-import { createPlugin } from './np_ready';
-import { addAllExtensions } from './np_ready/extend_index_management';
-
-if (chrome.getInjected('ilmUiEnabled')) {
-  // We have to initialize this outside of the NP lifecycle, otherwise these extensions won't
-  // be available in Index Management unless the user visits ILM first.
-  if ((npSetup.plugins as any).indexManagement) {
-    addAllExtensions((npSetup.plugins as any).indexManagement.extensionsService);
-  }
-
-  // This method handles the cleanup needed when route is scope is destroyed.  It also prevents Angular
-  // from destroying scope when route changes and both old route and new route are this same route.
-  const manageAngularLifecycle = ($scope: any, $route: any, unmount: () => void) => {
-    const lastRoute = $route.current;
-    const deregister = $scope.$on('$locationChangeSuccess', () => {
-      const currentRoute = $route.current;
-      // if templates are the same we are on the same route
-      if (lastRoute.$$route.template === currentRoute.$$route.template) {
-        // this prevents angular from destroying scope
-        $route.current = lastRoute;
-      }
-    });
-    $scope.$on('$destroy', () => {
-      if (deregister) {
-        deregister();
-      }
-      unmount();
-    });
-  };
-
-  // Once this app no longer depends upon Angular's routing (e.g. for the "redirect" service), we can
-  // use the Management plugin's API to register this app within the Elasticsearch section.
-  const esSection = management.getSection('elasticsearch');
-  esSection.register('index_lifecycle_policies', {
-    visible: true,
-    display: PLUGIN.TITLE,
-    order: 2,
-    url: `#${BASE_PATH}policies`,
-  });
-
-  const REACT_ROOT_ID = 'indexLifecycleManagementReactRoot';
-
-  const template = `<kbn-management-app section="elasticsearch/index_lifecycle_policies">
-    <div id="${REACT_ROOT_ID}" class="policyTable__horizontalScrollContainer"/>
-  </kbn-management-app>
-  `;
-
-  routes.when(`${BASE_PATH}:view?/:action?/:id?`, {
-    template,
-    controllerAs: 'indexLifecycleManagement',
-    controller: class IndexLifecycleManagementController {
-      constructor($scope: any, $route: any, kbnUrl: any, $rootScope: any) {
-        $scope.$$postDigest(() => {
-          const element = document.getElementById(REACT_ROOT_ID)!;
-          const { core } = npSetup;
-
-          const coreDependencies = {
-            ...core,
-            application: {
-              ...core.application,
-              async register(app: App<any>) {
-                const unmountApp = await app.mount({ ...npStart } as any, {
-                  element,
-                  appBasePath: '',
-                  onAppLeave: () => undefined,
-                  // TODO: adapt to use Core's ScopedHistory
-                  history: {} as any,
-                });
-                manageAngularLifecycle($scope, $route, unmountApp as any);
-              },
-            },
-          };
-
-          // The Plugin interface won't allow us to pass __LEGACY as a third argument, so we'll just
-          // sneak it inside of the plugins argument for now.
-          const pluginDependencies = {
-            __LEGACY: {
-              redirect: (path: string) => {
-                $scope.$evalAsync(() => {
-                  kbnUrl.redirect(path);
-                });
-              },
-              createUiStatsReporter,
-            },
-          };
-
-          const plugin = createPlugin({} as any);
-          plugin.setup(coreDependencies, pluginDependencies);
-        });
-      }
-    } as any,
-  } as any);
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/_index_lifecycle_management.scss b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/_index_lifecycle_management.scss
deleted file mode 100644
index 96c6d1a938c61..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/_index_lifecycle_management.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-.policyTable__horizontalScrollContainer {
-  overflow-x: auto;
-  max-width: 100%;
-}
-
-.policyTable__horizontalScroll {
-  min-width: 800px;
-  width: 100%;
-}
-
-.policyTable__link {
-  font-weight: 400;
-}
-
-.ilmEditPolicyPageContent {
-  max-width: 1200px !important;
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.scss b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.scss
deleted file mode 100644
index 53e90e2aae35b..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-// Import the EUI global scope so we can use EUI constants
-@import 'src/legacy/ui/public/styles/_styling_constants';
-@import 'index_lifecycle_management';
\ No newline at end of file
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.tsx b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.tsx
deleted file mode 100644
index b87a633d65c9c..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/index.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import { render, unmountComponentAtNode } from 'react-dom';
-import { Provider } from 'react-redux';
-import { DocLinksStart, ToastsSetup, HttpSetup, FatalErrorsSetup } from 'src/core/public';
-
-import { App } from './app';
-import { indexLifecycleManagementStore } from './store';
-import { init as initHttp } from './services/http';
-import { init as initNavigation } from './services/navigation';
-import { init as initDocumentation } from './services/documentation';
-import { init as initUiMetric } from './services/ui_metric';
-import { init as initNotification } from './services/notification';
-
-export interface LegacySetup {
-  redirect: any;
-  createUiStatsReporter: any;
-}
-
-interface AppDependencies {
-  legacy: LegacySetup;
-  I18nContext: any;
-  http: HttpSetup;
-  toasts: ToastsSetup;
-  fatalErrors: FatalErrorsSetup;
-  docLinks: DocLinksStart;
-  element: HTMLElement;
-}
-
-export const renderApp = (appDependencies: AppDependencies) => {
-  const {
-    legacy: { redirect, createUiStatsReporter },
-    I18nContext,
-    http,
-    toasts,
-    fatalErrors,
-    docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
-    element,
-  } = appDependencies;
-
-  // Initialize services
-  initHttp(http);
-  initNavigation(redirect);
-  initDocumentation(`${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/`);
-  initUiMetric(createUiStatsReporter);
-  initNotification(toasts, fatalErrors);
-
-  render(
-    <I18nContext>
-      <Provider store={indexLifecycleManagementStore()}>
-        <App />
-      </Provider>
-    </I18nContext>,
-    element
-  );
-
-  return () => unmountComponentAtNode(element);
-};
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/api.js b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/api.js
deleted file mode 100644
index f13bbcb6162b8..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/api.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import {
-  UIM_POLICY_DELETE,
-  UIM_POLICY_ATTACH_INDEX,
-  UIM_POLICY_ATTACH_INDEX_TEMPLATE,
-  UIM_POLICY_DETACH_INDEX,
-  UIM_INDEX_RETRY_STEP,
-} from '../constants';
-
-import { trackUiMetric } from './ui_metric';
-import { sendGet, sendPost, sendDelete } from './http';
-
-// The extend_index_management module that we support an injected httpClient here.
-
-export async function loadNodes(httpClient) {
-  return await sendGet(`nodes/list`, httpClient);
-}
-
-export async function loadNodeDetails(selectedNodeAttrs, httpClient) {
-  return await sendGet(`nodes/${selectedNodeAttrs}/details`, httpClient);
-}
-
-export async function loadIndexTemplates(httpClient) {
-  return await sendGet(`templates`, httpClient);
-}
-
-export async function loadIndexTemplate(templateName, httpClient) {
-  if (!templateName) {
-    return {};
-  }
-  return await sendGet(`templates/${templateName}`, httpClient);
-}
-
-export async function loadPolicies(withIndices, httpClient) {
-  const query = withIndices ? '?withIndices=true' : '';
-  return await sendGet('policies', query, httpClient);
-}
-
-export async function savePolicy(policy, httpClient) {
-  return await sendPost(`policies`, policy, httpClient);
-}
-
-export async function deletePolicy(policyName, httpClient) {
-  const response = await sendDelete(`policies/${encodeURIComponent(policyName)}`, httpClient);
-  // Only track successful actions.
-  trackUiMetric('count', UIM_POLICY_DELETE);
-  return response;
-}
-
-export const retryLifecycleForIndex = async (indexNames, httpClient) => {
-  const response = await sendPost(`index/retry`, { indexNames }, httpClient);
-  // Only track successful actions.
-  trackUiMetric('count', UIM_INDEX_RETRY_STEP);
-  return response;
-};
-
-export const removeLifecycleForIndex = async (indexNames, httpClient) => {
-  const response = await sendPost(`index/remove`, { indexNames }, httpClient);
-  // Only track successful actions.
-  trackUiMetric('count', UIM_POLICY_DETACH_INDEX);
-  return response;
-};
-
-export const addLifecyclePolicyToIndex = async (body, httpClient) => {
-  const response = await sendPost(`index/add`, body, httpClient);
-  // Only track successful actions.
-  trackUiMetric('count', UIM_POLICY_ATTACH_INDEX);
-  return response;
-};
-
-export const addLifecyclePolicyToTemplate = async (body, httpClient) => {
-  const response = await sendPost(`template`, body, httpClient);
-  // Only track successful actions.
-  trackUiMetric('count', UIM_POLICY_ATTACH_INDEX_TEMPLATE);
-  return response;
-};
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/plugin.tsx b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/plugin.tsx
deleted file mode 100644
index e2897f09fa892..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/plugin.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
-import { PLUGIN } from '../../common/constants';
-import { LegacySetup } from './application';
-
-interface PluginsSetup {
-  __LEGACY: LegacySetup;
-}
-
-export class IndexLifecycleManagementPlugin implements Plugin<void, void, any, any> {
-  setup(core: CoreSetup, plugins: PluginsSetup) {
-    // Extract individual core dependencies.
-    const {
-      application,
-      notifications: { toasts },
-      fatalErrors,
-      http,
-    } = core;
-
-    // The Plugin interface won't allow us to pass __LEGACY as a third argument, so we'll just
-    // sneak it inside of the plugins parameter for now.
-    const { __LEGACY } = plugins;
-
-    application.register({
-      id: PLUGIN.ID,
-      title: PLUGIN.TITLE,
-      async mount(config, mountPoint) {
-        const {
-          core: {
-            docLinks,
-            i18n: { Context: I18nContext },
-          },
-        } = config;
-
-        const { element } = mountPoint;
-        const { renderApp } = await import('./application');
-
-        // Inject all dependencies into our app.
-        return renderApp({
-          legacy: { ...__LEGACY },
-          I18nContext,
-          http,
-          toasts,
-          fatalErrors,
-          docLinks,
-          element,
-        });
-      },
-    });
-  }
-  start(core: CoreStart, plugins: any) {}
-  stop() {}
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/call_with_request_factory.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/call_with_request_factory.ts
deleted file mode 100644
index 1b28dc4fde4f7..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/call_with_request_factory.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { once } from 'lodash';
-import { Legacy } from 'kibana';
-
-const callWithRequest = once((server: Legacy.Server): any => {
-  const cluster = server.plugins.elasticsearch.getCluster('data');
-  return cluster.callWithRequest;
-});
-
-export const callWithRequestFactory = (server: Legacy.Server, request: any) => {
-  return (...args: any[]) => {
-    return callWithRequest(server)(request, ...args);
-  };
-};
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/index.ts
deleted file mode 100644
index 787814d87dff9..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/call_with_request_factory/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { callWithRequestFactory } from './call_with_request_factory';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js
deleted file mode 100644
index 933fda01c055d..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import expect from '@kbn/expect';
-import { set } from 'lodash';
-import { checkLicense } from '../check_license';
-
-describe('check_license', function() {
-  let mockLicenseInfo;
-  beforeEach(() => (mockLicenseInfo = {}));
-
-  describe('license information is undefined', () => {
-    beforeEach(() => (mockLicenseInfo = undefined));
-
-    it('should set isAvailable to false', () => {
-      expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false);
-    });
-
-    it('should set showLinks to true', () => {
-      expect(checkLicense(mockLicenseInfo).showLinks).to.be(true);
-    });
-
-    it('should set enableLinks to false', () => {
-      expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false);
-    });
-
-    it('should set a message', () => {
-      expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined);
-    });
-  });
-
-  describe('license information is not available', () => {
-    beforeEach(() => (mockLicenseInfo.isAvailable = () => false));
-
-    it('should set isAvailable to false', () => {
-      expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false);
-    });
-
-    it('should set showLinks to true', () => {
-      expect(checkLicense(mockLicenseInfo).showLinks).to.be(true);
-    });
-
-    it('should set enableLinks to false', () => {
-      expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false);
-    });
-
-    it('should set a message', () => {
-      expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined);
-    });
-  });
-
-  describe('license information is available', () => {
-    beforeEach(() => {
-      mockLicenseInfo.isAvailable = () => true;
-      set(mockLicenseInfo, 'license.getType', () => 'basic');
-    });
-
-    describe('& license is > basic', () => {
-      beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true));
-
-      describe('& license is active', () => {
-        beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true));
-
-        it('should set isAvailable to true', () => {
-          expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true);
-        });
-
-        it('should set showLinks to true', () => {
-          expect(checkLicense(mockLicenseInfo).showLinks).to.be(true);
-        });
-
-        it('should set enableLinks to true', () => {
-          expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true);
-        });
-
-        it('should not set a message', () => {
-          expect(checkLicense(mockLicenseInfo).message).to.be(undefined);
-        });
-      });
-
-      describe('& license is expired', () => {
-        beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false));
-
-        it('should set isAvailable to false', () => {
-          expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false);
-        });
-
-        it('should set showLinks to true', () => {
-          expect(checkLicense(mockLicenseInfo).showLinks).to.be(true);
-        });
-
-        it('should set enableLinks to false', () => {
-          expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false);
-        });
-
-        it('should set a message', () => {
-          expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined);
-        });
-      });
-    });
-
-    describe('& license is basic', () => {
-      beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true));
-
-      describe('& license is active', () => {
-        beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true));
-
-        it('should set isAvailable to true', () => {
-          expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true);
-        });
-
-        it('should set showLinks to true', () => {
-          expect(checkLicense(mockLicenseInfo).showLinks).to.be(true);
-        });
-
-        it('should set enableLinks to true', () => {
-          expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true);
-        });
-
-        it('should not set a message', () => {
-          expect(checkLicense(mockLicenseInfo).message).to.be(undefined);
-        });
-      });
-
-      describe('& license is expired', () => {
-        beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false));
-
-        it('should set isAvailable to false', () => {
-          expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false);
-        });
-
-        it('should set showLinks to true', () => {
-          expect(checkLicense(mockLicenseInfo).showLinks).to.be(true);
-        });
-
-        it('should set a message', () => {
-          expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined);
-        });
-      });
-    });
-  });
-});
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.ts
deleted file mode 100644
index b35ab14964d55..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { i18n } from '@kbn/i18n';
-
-export function checkLicense(xpackLicenseInfo: any): any {
-  const pluginName = 'Index Lifecycle Policies';
-
-  // If, for some reason, we cannot get the license information
-  // from Elasticsearch, assume worst case and disable
-  if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) {
-    return {
-      isAvailable: false,
-      showLinks: true,
-      enableLinks: false,
-      message: i18n.translate('xpack.indexLifecycleMgmt.checkLicense.errorUnavailableMessage', {
-        defaultMessage:
-          'You cannot use {pluginName} because license information is not available at this time.',
-        values: { pluginName },
-      }),
-    };
-  }
-
-  const VALID_LICENSE_MODES = ['basic', 'standard', 'gold', 'platinum', 'enterprise', 'trial'];
-
-  const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES);
-  const isLicenseActive = xpackLicenseInfo.license.isActive();
-  const licenseType = xpackLicenseInfo.license.getType();
-
-  // License is not valid
-  if (!isLicenseModeValid) {
-    return {
-      isAvailable: false,
-      showLinks: false,
-      message: i18n.translate('xpack.indexLifecycleMgmt.checkLicense.errorUnsupportedMessage', {
-        defaultMessage:
-          'Your {licenseType} license does not support {pluginName}. Please upgrade your license.',
-        values: { licenseType, pluginName },
-      }),
-    };
-  }
-
-  // License is valid but not active
-  if (!isLicenseActive) {
-    return {
-      isAvailable: false,
-      showLinks: true,
-      enableLinks: false,
-      message: i18n.translate('xpack.indexLifecycleMgmt.checkLicense.errorExpiredMessage', {
-        defaultMessage:
-          'You cannot use {pluginName} because your {licenseType} license has expired.',
-        values: { pluginName, licenseType },
-      }),
-    };
-  }
-
-  // License is valid and active
-  return {
-    isAvailable: true,
-    showLinks: true,
-    enableLinks: true,
-  };
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_custom_error.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_custom_error.js
deleted file mode 100644
index f9c102be7a1ff..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_custom_error.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import expect from '@kbn/expect';
-import { wrapCustomError } from '../wrap_custom_error';
-
-describe('wrap_custom_error', () => {
-  describe('#wrapCustomError', () => {
-    it('should return a Boom object', () => {
-      const originalError = new Error('I am an error');
-      const statusCode = 404;
-      const wrappedError = wrapCustomError(originalError, statusCode);
-
-      expect(wrappedError.isBoom).to.be(true);
-      expect(wrappedError.output.statusCode).to.equal(statusCode);
-    });
-  });
-});
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_es_error.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_es_error.js
deleted file mode 100644
index fe2b6cce652f1..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_es_error.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import expect from '@kbn/expect';
-import { wrapEsError } from '../wrap_es_error';
-
-describe('wrap_es_error', () => {
-  describe('#wrapEsError', () => {
-    let originalError;
-    beforeEach(() => {
-      originalError = new Error('I am an error');
-      originalError.statusCode = 404;
-    });
-
-    it('should return a Boom object', () => {
-      const wrappedError = wrapEsError(originalError);
-
-      expect(wrappedError.isBoom).to.be(true);
-    });
-
-    it('should return the correct Boom object', () => {
-      const wrappedError = wrapEsError(originalError);
-
-      expect(wrappedError.output.statusCode).to.be(originalError.statusCode);
-      expect(wrappedError.output.payload.message).to.be(originalError.message);
-    });
-
-    it('should return the correct Boom object with custom message', () => {
-      const wrappedError = wrapEsError(originalError, { 404: 'No encontrado!' });
-
-      expect(wrappedError.output.statusCode).to.be(originalError.statusCode);
-      expect(wrappedError.output.payload.message).to.be('No encontrado!');
-    });
-  });
-});
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_unknown_error.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_unknown_error.js
deleted file mode 100644
index 85e0b2b3033ad..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/__tests__/wrap_unknown_error.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import expect from '@kbn/expect';
-import { wrapUnknownError } from '../wrap_unknown_error';
-
-describe('wrap_unknown_error', () => {
-  describe('#wrapUnknownError', () => {
-    it('should return a Boom object', () => {
-      const originalError = new Error('I am an error');
-      const wrappedError = wrapUnknownError(originalError);
-
-      expect(wrappedError.isBoom).to.be(true);
-    });
-  });
-});
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/index.ts
deleted file mode 100644
index f275f15637091..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { wrapCustomError } from './wrap_custom_error';
-export { wrapEsError } from './wrap_es_error';
-export { wrapUnknownError } from './wrap_unknown_error';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_custom_error.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_custom_error.ts
deleted file mode 100644
index c5780e7c83fb5..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_custom_error.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import Boom from 'boom';
-
-/**
- * Wraps a custom error into a Boom error response and returns it
- *
- * @param err Object error
- * @param statusCode Error status code
- * @return Object Boom error response
- */
-export function wrapCustomError(err: any, statusCode: any): any {
-  return Boom.boomify(err, { statusCode });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_es_error.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_es_error.ts
deleted file mode 100644
index 6980a5afa5eac..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_es_error.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import Boom from 'boom';
-
-/**
- * Wraps an error thrown by the ES JS client into a Boom error response and returns it
- *
- * @param err Object Error thrown by ES JS client
- * @param statusCodeToMessageMap Object Optional map of HTTP status codes => error messages
- * @return Object Boom error response
- */
-export function wrapEsError(err: any, statusCodeToMessageMap: any = {}): any {
-  const statusCode = err.statusCode;
-
-  // If no custom message if specified for the error's status code, just
-  // wrap the error as a Boom error response and return it
-  if (!statusCodeToMessageMap[statusCode]) {
-    return Boom.boomify(err, { statusCode });
-  }
-
-  // Otherwise, use the custom message to create a Boom error response and
-  // return it
-  const message = statusCodeToMessageMap[statusCode];
-  return new Boom(message, { statusCode });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.ts
deleted file mode 100644
index ede1baec286f3..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import Boom from 'boom';
-
-/**
- * Wraps an unknown error into a Boom error response and returns it
- *
- * @param err Object Unknown error
- * @return Object Boom error response
- */
-export function wrapUnknownError(err: any): any {
-  return Boom.boomify(err);
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/is_es_error/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/is_es_error/index.ts
deleted file mode 100644
index a9a3c61472d8c..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/is_es_error/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { isEsError } from './is_es_error';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js
deleted file mode 100644
index 4d3b33f8b3af3..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import expect from '@kbn/expect';
-import { licensePreRoutingFactory } from '../license_pre_routing_factory';
-
-describe('license_pre_routing_factory', () => {
-  describe('#reportingFeaturePreRoutingFactory', () => {
-    let mockServer;
-    let mockLicenseCheckResults;
-
-    beforeEach(() => {
-      mockServer = {
-        plugins: {
-          xpack_main: {
-            info: {
-              feature: () => ({
-                getLicenseCheckResults: () => mockLicenseCheckResults,
-              }),
-            },
-          },
-        },
-      };
-    });
-
-    it('only instantiates one instance per server', () => {
-      const firstInstance = licensePreRoutingFactory(mockServer);
-      const secondInstance = licensePreRoutingFactory(mockServer);
-
-      expect(firstInstance).to.be(secondInstance);
-    });
-
-    describe('isAvailable is false', () => {
-      beforeEach(() => {
-        mockLicenseCheckResults = {
-          isAvailable: false,
-        };
-      });
-
-      it('replies with 403', () => {
-        const licensePreRouting = licensePreRoutingFactory(mockServer);
-        const stubRequest = {};
-        expect(() => licensePreRouting(stubRequest)).to.throwException(response => {
-          expect(response).to.be.an(Error);
-          expect(response.isBoom).to.be(true);
-          expect(response.output.statusCode).to.be(403);
-        });
-      });
-    });
-
-    describe('isAvailable is true', () => {
-      beforeEach(() => {
-        mockLicenseCheckResults = {
-          isAvailable: true,
-        };
-      });
-
-      it('replies with nothing', () => {
-        const licensePreRouting = licensePreRoutingFactory(mockServer);
-        const stubRequest = {};
-        const response = licensePreRouting(stubRequest);
-        expect(response).to.be(null);
-      });
-    });
-  });
-});
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts
deleted file mode 100644
index e348125967c14..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { once } from 'lodash';
-import { Legacy } from 'kibana';
-
-import { PLUGIN } from '../../../common/constants';
-import { wrapCustomError } from '../error_wrappers';
-
-export const licensePreRoutingFactory = once((server: Legacy.Server) => {
-  const xpackMainPlugin = server.plugins.xpack_main;
-
-  // License checking and enable/disable logic
-  function licensePreRouting() {
-    const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN.ID).getLicenseCheckResults();
-    if (!licenseCheckResults.isAvailable) {
-      const error = new Error(licenseCheckResults.message);
-      const statusCode = 403;
-      throw wrapCustomError(error, statusCode);
-    }
-
-    return null;
-  }
-
-  return licensePreRouting;
-});
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/index.ts
deleted file mode 100644
index 7b0f97c38d129..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { registerLicenseChecker } from './register_license_checker';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/register_license_checker.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/register_license_checker.ts
deleted file mode 100644
index 8e3b89fa20e33..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/register_license_checker/register_license_checker.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { Legacy } from 'kibana';
-// @ts-ignore
-import { mirrorPluginStatus } from '../../../../../server/lib/mirror_plugin_status';
-import { PLUGIN } from '../../../common/constants';
-import { checkLicense } from '../check_license';
-
-export function registerLicenseChecker(server: Legacy.Server) {
-  const xpackMainPlugin = server.plugins.xpack_main as any;
-  const ilmPlugin = (server.plugins as any).index_lifecycle_management;
-
-  mirrorPluginStatus(xpackMainPlugin, ilmPlugin);
-  xpackMainPlugin.status.once('green', () => {
-    // Register a function that is called whenever the xpack info changes,
-    // to re-compute the license check results for this plugin
-    xpackMainPlugin.info.feature(PLUGIN.ID).registerLicenseCheckResultsGenerator(checkLicense);
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/index.ts
deleted file mode 100644
index 82fb2e3b2a372..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { registerIndexRoutes } from './register_index_routes';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts
deleted file mode 100644
index c3e235220931c..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function addLifecyclePolicy(
-  callWithRequest: any,
-  indexName: string,
-  policyName: string,
-  alias: string
-) {
-  const body = {
-    lifecycle: {
-      name: policyName,
-      rollover_alias: alias,
-    },
-  };
-
-  const params = {
-    method: 'PUT',
-    path: `/${encodeURIComponent(indexName)}/_settings`,
-    body,
-  };
-
-  return callWithRequest('transport.request', params);
-}
-
-export function registerAddPolicyRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/index/add',
-    method: 'POST',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-      const { indexName, policyName, alias } = request.payload as any;
-      try {
-        const response = await addLifecyclePolicy(callWithRequest, indexName, policyName, alias);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts
deleted file mode 100644
index ed3b5a97a3b42..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function removeLifecycle(callWithRequest: any, indexNames: string[]) {
-  const responses = [];
-  for (let i = 0; i < indexNames.length; i++) {
-    const indexName = indexNames[i];
-    const params = {
-      method: 'POST',
-      path: `/${encodeURIComponent(indexName)}/_ilm/remove`,
-      ignore: [404],
-    };
-
-    responses.push(callWithRequest('transport.request', params));
-  }
-  return Promise.all(responses);
-}
-
-export function registerRemoveRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/index/remove',
-    method: 'POST',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-
-      try {
-        const response = await removeLifecycle(callWithRequest, request.payload.indexNames);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts
deleted file mode 100644
index 89278edbecea2..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function retryLifecycle(callWithRequest: any, indexNames: string[]) {
-  const responses = [];
-  for (let i = 0; i < indexNames.length; i++) {
-    const indexName = indexNames[i];
-    const params = {
-      method: 'POST',
-      path: `/${encodeURIComponent(indexName)}/_ilm/retry`,
-      ignore: [404],
-    };
-
-    responses.push(callWithRequest('transport.request', params));
-  }
-  return Promise.all(responses);
-}
-
-export function registerRetryRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/index/retry',
-    method: 'POST',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-
-      try {
-        const response = await retryLifecycle(callWithRequest, request.payload.indexNames);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/constants.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/constants.ts
deleted file mode 100644
index 4392dacac8fa4..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/constants.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export const NODE_ATTRS_KEYS_TO_IGNORE: string[] = [
-  'ml.enabled',
-  'ml.machine_memory',
-  'ml.max_open_jobs',
-  // Used by ML to identify nodes that have transform enabled:
-  // https://github.com/elastic/elasticsearch/pull/52712/files#diff-225cc2c1291b4c60a8c3412a619094e1R147
-  'transform.node',
-  'xpack.installed',
-];
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts
deleted file mode 100644
index ef0ac271ae60e..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { registerNodesRoutes } from './register_nodes_routes';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts
deleted file mode 100644
index c2c3f8bf07028..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-function findMatchingNodes(stats: any, nodeAttrs: string): any {
-  return Object.entries(stats.nodes).reduce((accum: any[], [nodeId, nodeStats]: [any, any]) => {
-    const attributes = nodeStats.attributes || {};
-    for (const [key, value] of Object.entries(attributes)) {
-      if (`${key}:${value}` === nodeAttrs) {
-        accum.push({
-          nodeId,
-          stats: nodeStats,
-        });
-        break;
-      }
-    }
-    return accum;
-  }, []);
-}
-
-async function fetchNodeStats(callWithRequest: any): Promise<any> {
-  const params = {
-    format: 'json',
-  };
-
-  return await callWithRequest('nodes.stats', params);
-}
-
-export function registerDetailsRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/nodes/{nodeAttrs}/details',
-    method: 'GET',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-
-      try {
-        const stats = await fetchNodeStats(callWithRequest);
-        const response = findMatchingNodes(stats, request.params.nodeAttrs);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts
deleted file mode 100644
index edbe4289ed83c..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-import { NODE_ATTRS_KEYS_TO_IGNORE } from './constants';
-
-function convertStatsIntoList(stats: any, attributesToBeFiltered: string[]): any {
-  return Object.entries(stats.nodes).reduce((accum: any, [nodeId, nodeStats]: [any, any]) => {
-    const attributes = nodeStats.attributes || {};
-    for (const [key, value] of Object.entries(attributes)) {
-      if (!attributesToBeFiltered.includes(key)) {
-        const attributeString = `${key}:${value}`;
-        accum[attributeString] = accum[attributeString] || [];
-        accum[attributeString].push(nodeId);
-      }
-    }
-    return accum;
-  }, {});
-}
-
-async function fetchNodeStats(callWithRequest: any): Promise<any> {
-  const params = {
-    format: 'json',
-  };
-
-  return await callWithRequest('nodes.stats', params);
-}
-
-export function registerListRoute(server: any) {
-  const config = server.config();
-  const filteredNodeAttributes = config.get('xpack.ilm.filteredNodeAttributes');
-  const attributesToBeFiltered = [...NODE_ATTRS_KEYS_TO_IGNORE, ...filteredNodeAttributes];
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/nodes/list',
-    method: 'GET',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-
-      try {
-        const stats = await fetchNodeStats(callWithRequest);
-        const response = convertStatsIntoList(stats, attributesToBeFiltered);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/index.ts
deleted file mode 100644
index 7c6103a3389ab..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { registerPoliciesRoutes } from './register_policies_routes';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
deleted file mode 100644
index f6bc96dd498a4..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function createPolicy(callWithRequest: any, policy: any): Promise<any> {
-  const body = {
-    policy: {
-      phases: policy.phases,
-    },
-  };
-  const params = {
-    method: 'PUT',
-    path: `/_ilm/policy/${encodeURIComponent(policy.name)}`,
-    ignore: [404],
-    body,
-  };
-
-  return await callWithRequest('transport.request', params);
-}
-
-export function registerCreateRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/policies',
-    method: 'POST',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-
-      try {
-        const response = await createPolicy(callWithRequest, request.payload);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts
deleted file mode 100644
index c84f2efd92d8f..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function deletePolicies(policyNames: string, callWithRequest: any): Promise<any> {
-  const params = {
-    method: 'DELETE',
-    path: `/_ilm/policy/${encodeURIComponent(policyNames)}`,
-    // we allow 404 since they may have no policies
-    ignore: [404],
-  };
-
-  return await callWithRequest('transport.request', params);
-}
-
-export function registerDeleteRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/policies/{policyNames}',
-    method: 'DELETE',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-      const { policyNames } = request.params;
-      try {
-        await deletePolicies(policyNames, callWithRequest);
-        return {};
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts
deleted file mode 100644
index c65f849a47d87..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-function formatPolicies(policiesMap: any): any {
-  if (policiesMap.status === 404) {
-    return [];
-  }
-
-  return Object.keys(policiesMap).reduce((accum: any[], lifecycleName: string) => {
-    const policyEntry = policiesMap[lifecycleName];
-    accum.push({
-      ...policyEntry,
-      name: lifecycleName,
-    });
-    return accum;
-  }, []);
-}
-
-async function fetchPolicies(callWithRequest: any): Promise<any> {
-  const params = {
-    method: 'GET',
-    path: '/_ilm/policy',
-    // we allow 404 since they may have no policies
-    ignore: [404],
-  };
-
-  return await callWithRequest('transport.request', params);
-}
-async function addLinkedIndices(policiesMap: any, callWithRequest: any) {
-  if (policiesMap.status === 404) {
-    return policiesMap;
-  }
-  const params = {
-    method: 'GET',
-    path: '/*/_ilm/explain',
-    // we allow 404 since they may have no policies
-    ignore: [404],
-  };
-
-  const policyExplanation: any = await callWithRequest('transport.request', params);
-  Object.entries(policyExplanation.indices).forEach(([indexName, { policy }]: [string, any]) => {
-    if (policy && policiesMap[policy]) {
-      policiesMap[policy].linkedIndices = policiesMap[policy].linkedIndices || [];
-      policiesMap[policy].linkedIndices.push(indexName);
-    }
-  });
-}
-
-export function registerFetchRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/policies',
-    method: 'GET',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-      const { withIndices } = request.query;
-      try {
-        const policiesMap = await fetchPolicies(callWithRequest);
-        if (withIndices) {
-          await addLinkedIndices(policiesMap, callWithRequest);
-        }
-        return formatPolicies(policiesMap);
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/index.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/index.ts
deleted file mode 100644
index dc9a0acaaf09b..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { registerTemplatesRoutes } from './register_templates_routes';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts
deleted file mode 100644
index 57e5a91f60f5b..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { merge } from 'lodash';
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function getIndexTemplate(callWithRequest: any, templateName: string): Promise<any> {
-  const response = await callWithRequest('indices.getTemplate', { name: templateName });
-  return response[templateName];
-}
-
-async function updateIndexTemplate(callWithRequest: any, indexTemplatePatch: any): Promise<any> {
-  // Fetch existing template
-  const template = await getIndexTemplate(callWithRequest, indexTemplatePatch.templateName);
-  merge(template, {
-    settings: {
-      index: {
-        lifecycle: {
-          name: indexTemplatePatch.policyName,
-          rollover_alias: indexTemplatePatch.aliasName,
-        },
-      },
-    },
-  });
-
-  const params = {
-    method: 'PUT',
-    path: `/_template/${encodeURIComponent(indexTemplatePatch.templateName)}`,
-    ignore: [404],
-    body: template,
-  };
-
-  return await callWithRequest('transport.request', params);
-}
-
-export function registerAddPolicyRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/template',
-    method: 'POST',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-
-      try {
-        const response = await updateIndexTemplate(callWithRequest, request.payload);
-        return response;
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_get_route.ts b/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_get_route.ts
deleted file mode 100644
index 3edaea6e15818..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_get_route.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
-
-async function fetchTemplate(callWithRequest: any, templateName: string): Promise<any> {
-  const params = {
-    method: 'GET',
-    path: `/_template/${encodeURIComponent(templateName)}`,
-    // we allow 404 incase the user shutdown security in-between the check and now
-    ignore: [404],
-  };
-
-  return await callWithRequest('transport.request', params);
-}
-
-export function registerGetRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/templates/{templateName}',
-    method: 'GET',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
-      const templateName = request.params.templateName;
-
-      try {
-        const template = await fetchTemplate(callWithRequest, templateName);
-        return template[templateName];
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
-        }
-
-        return wrapUnknownError(err);
-      }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
-}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/shim.ts b/x-pack/legacy/plugins/index_lifecycle_management/shim.ts
deleted file mode 100644
index 18b3d9ef28b6a..0000000000000
--- a/x-pack/legacy/plugins/index_lifecycle_management/shim.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { Legacy } from 'kibana';
-
-export interface LegacySetup {
-  server: Legacy.Server;
-}
-
-export function createShim(server: Legacy.Server): LegacySetup {
-  return {
-    server,
-  };
-}
diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts
index 9eba98a526d2b..afca15203b970 100644
--- a/x-pack/legacy/plugins/index_management/index.ts
+++ b/x-pack/legacy/plugins/index_management/index.ts
@@ -4,6 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+// TODO: Remove this once CCR is migrated to the plugins directory.
 export function indexManagement(kibana: any) {
   return new kibana.Plugin({
     id: 'index_management',
diff --git a/x-pack/legacy/plugins/rollup/public/plugin.ts b/x-pack/legacy/plugins/rollup/public/plugin.ts
index 5782e88c3448b..17ec8a5a4aedf 100644
--- a/x-pack/legacy/plugins/rollup/public/plugin.ts
+++ b/x-pack/legacy/plugins/rollup/public/plugin.ts
@@ -24,7 +24,7 @@ import {
 // @ts-ignore
 import { CRUD_APP_BASE_PATH } from './crud_app/constants';
 import { ManagementSetup } from '../../../../../src/plugins/management/public';
-import { IndexMgmtSetup } from '../../../../plugins/index_management/public';
+import { IndexManagementPluginSetup } from '../../../../plugins/index_management/public';
 import { IndexPatternManagementSetup } from '../../../../../src/plugins/index_pattern_management/public';
 import { search } from '../../../../../src/plugins/data/public';
 // @ts-ignore
@@ -35,7 +35,7 @@ import { renderApp } from './application';
 export interface RollupPluginSetupDependencies {
   home?: HomePublicPluginSetup;
   management: ManagementSetup;
-  indexManagement?: IndexMgmtSetup;
+  indexManagement?: IndexManagementPluginSetup;
   indexPatternManagement: IndexPatternManagementSetup;
 }
 
diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts
index 090cb8a47377a..5f29ad160e052 100644
--- a/x-pack/legacy/plugins/rollup/server/plugin.ts
+++ b/x-pack/legacy/plugins/rollup/server/plugin.ts
@@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n';
 
 import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
 import { VisTypeTimeseriesSetup } from 'src/plugins/vis_type_timeseries/server';
-import { IndexMgmtSetup } from '../../../../plugins/index_management/server';
+import { IndexManagementPluginSetup } from '../../../../plugins/index_management/server';
 import { registerLicenseChecker } from '../../../server/lib/register_license_checker';
 import { PLUGIN } from '../common';
 import { ServerShim, RouteDependencies } from './types';
@@ -44,7 +44,7 @@ export class RollupsServerPlugin implements Plugin<void, void, any, any> {
       __LEGACY: ServerShim;
       usageCollection?: UsageCollectionSetup;
       metrics?: VisTypeTimeseriesSetup;
-      indexManagement?: IndexMgmtSetup;
+      indexManagement?: IndexManagementPluginSetup;
     }
   ) {
     const elasticsearch = await elasticsearchService.adminClient;
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap b/x-pack/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap
rename to x-pack/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/__snapshots__/policy_table.test.js.snap b/x-pack/plugins/index_lifecycle_management/__jest__/components/__snapshots__/policy_table.test.js.snap
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/__snapshots__/policy_table.test.js.snap
rename to x-pack/plugins/index_lifecycle_management/__jest__/components/__snapshots__/policy_table.test.js.snap
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js
similarity index 96%
rename from x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js
rename to x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js
index 9d143c4d3fc8e..bf4de823f1833 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js
@@ -13,13 +13,13 @@ import axiosXhrAdapter from 'axios/lib/adapters/xhr';
 import sinon from 'sinon';
 import { findTestSubject } from '@elastic/eui/lib/test';
 
-import { mountWithIntl } from '../../../../../test_utils/enzyme_helpers';
-import { fetchedPolicies, fetchedNodes } from '../../public/np_ready/application/store/actions';
-import { indexLifecycleManagementStore } from '../../public/np_ready/application/store';
-import { EditPolicy } from '../../public/np_ready/application/sections/edit_policy';
-import { init as initHttp } from '../../public/np_ready/application/services/http';
-import { init as initUiMetric } from '../../public/np_ready/application/services/ui_metric';
-import { init as initNotification } from '../../public/np_ready/application/services/notification';
+import { mountWithIntl } from '../../../../test_utils/enzyme_helpers';
+import { fetchedPolicies, fetchedNodes } from '../../public/application/store/actions';
+import { indexLifecycleManagementStore } from '../../public/application/store';
+import { EditPolicy } from '../../public/application/sections/edit_policy';
+import { init as initHttp } from '../../public/application/services/http';
+import { init as initUiMetric } from '../../public/application/services/ui_metric';
+import { init as initNotification } from '../../public/application/services/notification';
 import {
   positiveNumbersAboveZeroErrorMessage,
   positiveNumberRequiredMessage,
@@ -33,16 +33,14 @@ import {
   policyNameMustBeDifferentErrorMessage,
   policyNameAlreadyUsedErrorMessage,
   maximumDocumentsRequiredMessage,
-} from '../../public/np_ready/application/store/selectors/lifecycle';
+} from '../../public/application/store/selectors/lifecycle';
 
 initHttp(axios.create({ adapter: axiosXhrAdapter }), path => path);
-initUiMetric(() => () => {});
+initUiMetric({ reportUiStats: () => {} });
 initNotification({
   addDanger: () => {},
 });
 
-jest.mock('ui/new_platform');
-
 let server;
 let store;
 const policy = {
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js b/x-pack/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js
similarity index 91%
rename from x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js
rename to x-pack/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js
index a3a9c5e59bfa4..78c5c181eea62 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/components/policy_table.test.js
@@ -12,17 +12,15 @@ import axiosXhrAdapter from 'axios/lib/adapters/xhr';
 import sinon from 'sinon';
 import { findTestSubject, takeMountedSnapshot } from '@elastic/eui/lib/test';
 
-import { mountWithIntl } from '../../../../../test_utils/enzyme_helpers';
-import { fetchedPolicies } from '../../public/np_ready/application/store/actions';
-import { indexLifecycleManagementStore } from '../../public/np_ready/application/store';
-import { PolicyTable } from '../../public/np_ready/application/sections/policy_table';
-import { init as initHttp } from '../../public/np_ready/application/services/http';
-import { init as initUiMetric } from '../../public/np_ready/application/services/ui_metric';
+import { mountWithIntl } from '../../../../test_utils/enzyme_helpers';
+import { fetchedPolicies } from '../../public/application/store/actions';
+import { indexLifecycleManagementStore } from '../../public/application/store';
+import { PolicyTable } from '../../public/application/sections/policy_table';
+import { init as initHttp } from '../../public/application/services/http';
+import { init as initUiMetric } from '../../public/application/services/ui_metric';
 
 initHttp(axios.create({ adapter: axiosXhrAdapter }), path => path);
-initUiMetric(() => () => {});
-
-jest.mock('ui/new_platform');
+initUiMetric({ reportUiStats: () => {} });
 
 let server = null;
 
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js b/x-pack/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js
similarity index 93%
rename from x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js
rename to x-pack/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js
index d2619778617c3..900de27ca36ab 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js
@@ -8,7 +8,7 @@ import moment from 'moment-timezone';
 import axios from 'axios';
 import axiosXhrAdapter from 'axios/lib/adapters/xhr';
 
-import { mountWithIntl } from '../../../../test_utils/enzyme_helpers';
+import { mountWithIntl } from '../../../test_utils/enzyme_helpers';
 import {
   retryLifecycleActionExtension,
   removeLifecyclePolicyActionExtension,
@@ -16,21 +16,18 @@ import {
   ilmBannerExtension,
   ilmFilterExtension,
   ilmSummaryExtension,
-} from '../public/np_ready/extend_index_management';
-import { init as initHttp } from '../public/np_ready/application/services/http';
-import { init as initUiMetric } from '../public/np_ready/application/services/ui_metric';
+} from '../public/extend_index_management';
+import { init as initHttp } from '../public/application/services/http';
+import { init as initUiMetric } from '../public/application/services/ui_metric';
 
 // We need to init the http with a mock for any tests that depend upon the http service.
 // For example, add_lifecycle_confirm_modal makes an API request in its componentDidMount
 // lifecycle method. If we don't mock this, CI will fail with "Call retries were exceeded".
 initHttp(axios.create({ adapter: axiosXhrAdapter }), path => path);
-initUiMetric(() => () => {});
+initUiMetric({ reportUiStats: () => {} });
 
-jest.mock('ui/new_platform');
-jest.mock('../../../../plugins/index_management/public', async () => {
-  const { indexManagementMock } = await import(
-    '../../../../plugins/index_management/public/mocks.ts'
-  );
+jest.mock('../../../plugins/index_management/public', async () => {
+  const { indexManagementMock } = await import('../../../plugins/index_management/public/mocks.ts');
   return indexManagementMock.createSetup();
 });
 
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/common/constants/index.ts b/x-pack/plugins/index_lifecycle_management/common/constants/index.ts
similarity index 72%
rename from x-pack/legacy/plugins/index_lifecycle_management/common/constants/index.ts
rename to x-pack/plugins/index_lifecycle_management/common/constants/index.ts
index 9193efb561a0f..700039985eaf5 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/common/constants/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/common/constants/index.ts
@@ -5,12 +5,18 @@
  */
 
 import { i18n } from '@kbn/i18n';
+import { LicenseType } from '../../../licensing/common/types';
+
+const basicLicense: LicenseType = 'basic';
 
 export const PLUGIN = {
   ID: 'index_lifecycle_management',
+  minimumLicenseType: basicLicense,
   TITLE: i18n.translate('xpack.indexLifecycleMgmt.appTitle', {
     defaultMessage: 'Index Lifecycle Policies',
   }),
 };
 
 export const BASE_PATH = '/management/elasticsearch/index_lifecycle_management/';
+
+export const API_BASE_PATH = '/api/index_lifecycle_management';
diff --git a/x-pack/plugins/index_lifecycle_management/kibana.json b/x-pack/plugins/index_lifecycle_management/kibana.json
new file mode 100644
index 0000000000000..6385646b95789
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/kibana.json
@@ -0,0 +1,16 @@
+{
+  "id": "indexLifecycleManagement",
+  "version": "kibana",
+  "server": true,
+  "ui": true,
+  "requiredPlugins": [
+    "home",
+    "licensing",
+    "management"
+  ],
+  "optionalPlugins": [
+    "usageCollection",
+    "indexManagement"
+  ],
+  "configPath": ["xpack", "ilm"]
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/app.tsx b/x-pack/plugins/index_lifecycle_management/public/application/app.tsx
similarity index 94%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/app.tsx
rename to x-pack/plugins/index_lifecycle_management/public/application/app.tsx
index 6738d7caa4444..993dced20bbe6 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/app.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/app.tsx
@@ -8,7 +8,7 @@ import React, { useEffect } from 'react';
 import { HashRouter, Switch, Route, Redirect } from 'react-router-dom';
 import { METRIC_TYPE } from '@kbn/analytics';
 
-import { BASE_PATH } from '../../../common/constants';
+import { BASE_PATH } from '../../common/constants';
 import { UIM_APP_LOAD } from './constants';
 import { EditPolicy } from './sections/edit_policy';
 import { PolicyTable } from './sections/policy_table';
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/constants/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/constants/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/constants/index.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/constants/index.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/constants/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/constants/ui_metric.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/constants/ui_metric.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/constants/ui_metric.ts
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/index.tsx b/x-pack/plugins/index_lifecycle_management/public/application/index.tsx
new file mode 100644
index 0000000000000..a7d88d31e58fc
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/index.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { render, unmountComponentAtNode } from 'react-dom';
+import { Provider } from 'react-redux';
+import { I18nStart } from 'kibana/public';
+import { UnmountCallback } from 'src/core/public';
+
+import { App } from './app';
+import { indexLifecycleManagementStore } from './store';
+
+export const renderApp = (element: Element, I18nContext: I18nStart['Context']): UnmountCallback => {
+  render(
+    <I18nContext>
+      <Provider store={indexLifecycleManagementStore()}>
+        <App />
+      </Provider>
+    </I18nContext>,
+    element
+  );
+
+  return () => unmountComponentAtNode(element);
+};
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/active_badge.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/components/active_badge.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/active_badge.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/components/active_badge.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/components/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/components/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/learn_more_link.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/components/learn_more_link.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/learn_more_link.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/components/learn_more_link.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/optional_label.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/components/optional_label.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/optional_label.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/components/optional_label.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/phase_error_message.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/components/phase_error_message.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/components/phase_error_message.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/components/phase_error_message.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/cold_phase/cold_phase.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/cold_phase/cold_phase.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/cold_phase/cold_phase.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/cold_phase/cold_phase.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/cold_phase/cold_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/cold_phase/cold_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/cold_phase/cold_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/cold_phase/cold_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/cold_phase/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/cold_phase/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/cold_phase/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/cold_phase/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/delete_phase/delete_phase.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/delete_phase/delete_phase.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/delete_phase/delete_phase.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/delete_phase/delete_phase.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/delete_phase/delete_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/delete_phase/delete_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/delete_phase/delete_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/delete_phase/delete_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/delete_phase/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/delete_phase/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/delete_phase/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/delete_phase/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/hot_phase/hot_phase.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/hot_phase/hot_phase.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/hot_phase/hot_phase.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/hot_phase/hot_phase.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/hot_phase/hot_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/hot_phase/hot_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/hot_phase/hot_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/hot_phase/hot_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/hot_phase/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/hot_phase/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/hot_phase/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/hot_phase/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/min_age_input.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/min_age_input.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/min_age_input.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/min_age_input.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_allocation/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_allocation/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_allocation/node_allocation.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation/node_allocation.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_allocation/node_allocation.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation/node_allocation.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_allocation/node_allocation.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation/node_allocation.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_allocation/node_allocation.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation/node_allocation.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_attrs_details/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_attrs_details/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_attrs_details/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_attrs_details/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_attrs_details/node_attrs_details.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/policy_json_flyout.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/policy_json_flyout.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/set_priority_input.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/set_priority_input.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/set_priority_input.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/set_priority_input.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/warm_phase/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/warm_phase/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/warm_phase/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/warm_phase/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/warm_phase/warm_phase.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/warm_phase/warm_phase.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/warm_phase/warm_phase.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/warm_phase/warm_phase.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/warm_phase/warm_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/warm_phase/warm_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/components/warm_phase/warm_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/warm_phase/warm_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/edit_policy.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/edit_policy.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/edit_policy.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/edit_policy.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/form_errors.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_errors.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/form_errors.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_errors.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/index.d.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/index.d.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/index.d.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/index.d.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/edit_policy/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/no_match/components/no_match/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/no_match/components/no_match/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/no_match/components/no_match/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/no_match/components/no_match/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/no_match/components/no_match/no_match.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/no_match/components/no_match/no_match.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/no_match/components/no_match/no_match.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/no_match/components/no_match/no_match.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/no_match/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/no_match/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/no_match/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/no_match/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/add_policy_to_template_confirm_modal.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/add_policy_to_template_confirm_modal.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/add_policy_to_template_confirm_modal.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/add_policy_to_template_confirm_modal.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/confirm_delete.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/confirm_delete.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/confirm_delete.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/confirm_delete.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.container.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/policy_table.container.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.container.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/policy_table.container.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/policy_table.js
similarity index 98%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/policy_table.js
index 903161fe094fc..d406d86bc6ce7 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/policy_table/policy_table.js
@@ -37,8 +37,8 @@ import {
 
 import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
 
-import { getIndexListUri } from '../../../../../../../../../../plugins/index_management/public';
-import { BASE_PATH } from '../../../../../../../common/constants';
+import { getIndexListUri } from '../../../../../../../index_management/public';
+import { BASE_PATH } from '../../../../../../common/constants';
 import { UIM_EDIT_CLICK } from '../../../../constants';
 import { getPolicyPath } from '../../../../services/navigation';
 import { flattenPanelTree } from '../../../../services/flatten_panel_tree';
@@ -52,6 +52,7 @@ const COLUMNS = {
     label: i18n.translate('xpack.indexLifecycleMgmt.policyTable.headers.nameHeader', {
       defaultMessage: 'Name',
     }),
+    width: 200,
   },
   linkedIndices: {
     label: i18n.translate('xpack.indexLifecycleMgmt.policyTable.headers.linkedIndicesHeader', {
@@ -179,7 +180,6 @@ export class PolicyTable extends Component {
       return (
         /* eslint-disable-next-line @elastic/eui/href-or-on-click */
         <EuiLink
-          className="policyTable__link"
           data-test-subj="policyTablePolicyNameLink"
           href={getPolicyPath(value)}
           onClick={() => trackUiMetric('click', UIM_EDIT_CLICK)}
@@ -415,7 +415,7 @@ export class PolicyTable extends Component {
         tableContent = <EuiLoadingSpinner size="m" />;
       } else if (totalNumberOfPolicies > 0) {
         tableContent = (
-          <EuiTable className="policyTable__horizontalScroll">
+          <EuiTable>
             <EuiScreenReaderOnly>
               <caption role="status" aria-relevant="text" aria-live="polite">
                 <FormattedMessage
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/index.d.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/index.d.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/index.d.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/index.d.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/index.js b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/index.js
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/api.js b/x-pack/plugins/index_lifecycle_management/public/application/services/api.js
new file mode 100644
index 0000000000000..1cb2089ab66db
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/api.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import {
+  UIM_POLICY_DELETE,
+  UIM_POLICY_ATTACH_INDEX,
+  UIM_POLICY_ATTACH_INDEX_TEMPLATE,
+  UIM_POLICY_DETACH_INDEX,
+  UIM_INDEX_RETRY_STEP,
+} from '../constants';
+
+import { trackUiMetric } from './ui_metric';
+import { sendGet, sendPost, sendDelete } from './http';
+
+export async function loadNodes() {
+  return await sendGet(`nodes/list`);
+}
+
+export async function loadNodeDetails(selectedNodeAttrs) {
+  return await sendGet(`nodes/${selectedNodeAttrs}/details`);
+}
+
+export async function loadIndexTemplates() {
+  return await sendGet(`templates`);
+}
+
+export async function loadPolicies(withIndices) {
+  const query = withIndices ? '?withIndices=true' : '';
+  return await sendGet('policies', query);
+}
+
+export async function savePolicy(policy) {
+  return await sendPost(`policies`, policy);
+}
+
+export async function deletePolicy(policyName) {
+  const response = await sendDelete(`policies/${encodeURIComponent(policyName)}`);
+  // Only track successful actions.
+  trackUiMetric('count', UIM_POLICY_DELETE);
+  return response;
+}
+
+export const retryLifecycleForIndex = async indexNames => {
+  const response = await sendPost(`index/retry`, { indexNames });
+  // Only track successful actions.
+  trackUiMetric('count', UIM_INDEX_RETRY_STEP);
+  return response;
+};
+
+export const removeLifecycleForIndex = async indexNames => {
+  const response = await sendPost(`index/remove`, { indexNames });
+  // Only track successful actions.
+  trackUiMetric('count', UIM_POLICY_DETACH_INDEX);
+  return response;
+};
+
+export const addLifecyclePolicyToIndex = async body => {
+  const response = await sendPost(`index/add`, body);
+  // Only track successful actions.
+  trackUiMetric('count', UIM_POLICY_ATTACH_INDEX);
+  return response;
+};
+
+export const addLifecyclePolicyToTemplate = async body => {
+  const response = await sendPost(`template`, body);
+  // Only track successful actions.
+  trackUiMetric('count', UIM_POLICY_ATTACH_INDEX_TEMPLATE);
+  return response;
+};
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/api_errors.js b/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/api_errors.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/documentation.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/documentation.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/documentation.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/services/documentation.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/filter_items.js b/x-pack/plugins/index_lifecycle_management/public/application/services/filter_items.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/filter_items.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/filter_items.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/find_errors.js b/x-pack/plugins/index_lifecycle_management/public/application/services/find_errors.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/find_errors.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/find_errors.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/flatten_panel_tree.js b/x-pack/plugins/index_lifecycle_management/public/application/services/flatten_panel_tree.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/flatten_panel_tree.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/flatten_panel_tree.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/http.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/http.ts
similarity index 50%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/http.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/services/http.ts
index bbda1ebd2e0e5..47e96ea28bb8c 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/http.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/http.ts
@@ -20,16 +20,14 @@ function getFullPath(path: string): string {
   return apiPrefix;
 }
 
-// The extend_index_management module requires that we support an injected httpClient here.
-
-export function sendPost(path: string, payload: any, httpClient = _httpClient): any {
-  return httpClient.post(getFullPath(path), { body: JSON.stringify(payload) });
+export function sendPost(path: string, payload: any): any {
+  return _httpClient.post(getFullPath(path), { body: JSON.stringify(payload) });
 }
 
-export function sendGet(path: string, query: any, httpClient = _httpClient): any {
-  return httpClient.get(getFullPath(path), { query });
+export function sendGet(path: string, query: any): any {
+  return _httpClient.get(getFullPath(path), { query });
 }
 
-export function sendDelete(path: string, httpClient = _httpClient): any {
-  return httpClient.delete(getFullPath(path));
+export function sendDelete(path: string): any {
+  return _httpClient.delete(getFullPath(path));
 }
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/index.js b/x-pack/plugins/index_lifecycle_management/public/application/services/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/navigation.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/navigation.ts
similarity index 59%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/navigation.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/services/navigation.ts
index 943f9a49d0ab6..2d518ebb3015e 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/navigation.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/navigation.ts
@@ -4,18 +4,10 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { BASE_PATH } from '../../../../common/constants';
-
-// This depends upon Angular, which is why we use this provider pattern to access it within
-// our React app.
-let _redirect: any;
-
-export function init(redirect: any) {
-  _redirect = redirect;
-}
+import { BASE_PATH } from '../../../common/constants';
 
 export const goToPolicyList = () => {
-  _redirect(`${BASE_PATH}policies`);
+  window.location.hash = `${BASE_PATH}policies`;
 };
 
 export const getPolicyPath = (policyName: string): string => {
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/notification.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/notification.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/notification.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/services/notification.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/sort_table.js b/x-pack/plugins/index_lifecycle_management/public/application/services/sort_table.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/sort_table.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/sort_table.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/ui_metric.test.js b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/ui_metric.test.js
rename to x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
similarity index 85%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/ui_metric.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
index d9f2c26048317..ca6c0b44d5804 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/services/ui_metric.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
@@ -6,7 +6,8 @@
 
 import { get } from 'lodash';
 
-import { createUiStatsReporter } from '../../../../../../../../src/legacy/core_plugins/ui_metric/public';
+import { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
+import { UiStatsMetricType } from '@kbn/analytics';
 
 import {
   UIM_APP_NAME,
@@ -22,12 +23,10 @@ import {
 
 import { defaultColdPhase, defaultWarmPhase, defaultHotPhase } from '../store/defaults';
 
-export let trackUiMetric: ReturnType<typeof createUiStatsReporter>;
+export let trackUiMetric: (metricType: UiStatsMetricType, eventName: string) => void;
 
-export function init(getReporter: typeof createUiStatsReporter): void {
-  if (getReporter) {
-    trackUiMetric = getReporter(UIM_APP_NAME);
-  }
+export function init(usageCollection: UsageCollectionSetup): void {
+  trackUiMetric = usageCollection.reportUiStats.bind(usageCollection, UIM_APP_NAME);
 }
 
 export function getUiMetricsForPhases(phases: any): any {
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/general.js b/x-pack/plugins/index_lifecycle_management/public/application/store/actions/general.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/general.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/actions/general.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/index.js b/x-pack/plugins/index_lifecycle_management/public/application/store/actions/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/actions/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/lifecycle.js b/x-pack/plugins/index_lifecycle_management/public/application/store/actions/lifecycle.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/lifecycle.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/actions/lifecycle.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/nodes.js b/x-pack/plugins/index_lifecycle_management/public/application/store/actions/nodes.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/nodes.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/actions/nodes.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/policies.js b/x-pack/plugins/index_lifecycle_management/public/application/store/actions/policies.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/actions/policies.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/actions/policies.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/cold_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/store/defaults/cold_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/cold_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/defaults/cold_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/delete_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/store/defaults/delete_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/delete_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/defaults/delete_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/hot_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/store/defaults/hot_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/hot_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/defaults/hot_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/index.d.ts b/x-pack/plugins/index_lifecycle_management/public/application/store/defaults/index.d.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/index.d.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/store/defaults/index.d.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/index.js b/x-pack/plugins/index_lifecycle_management/public/application/store/defaults/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/defaults/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/warm_phase.js b/x-pack/plugins/index_lifecycle_management/public/application/store/defaults/warm_phase.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/defaults/warm_phase.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/defaults/warm_phase.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/index.d.ts b/x-pack/plugins/index_lifecycle_management/public/application/store/index.d.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/index.d.ts
rename to x-pack/plugins/index_lifecycle_management/public/application/store/index.d.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/index.js b/x-pack/plugins/index_lifecycle_management/public/application/store/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/general.js b/x-pack/plugins/index_lifecycle_management/public/application/store/reducers/general.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/general.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/reducers/general.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/index.js b/x-pack/plugins/index_lifecycle_management/public/application/store/reducers/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/reducers/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/nodes.js b/x-pack/plugins/index_lifecycle_management/public/application/store/reducers/nodes.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/nodes.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/reducers/nodes.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/policies.js b/x-pack/plugins/index_lifecycle_management/public/application/store/reducers/policies.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/reducers/policies.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/reducers/policies.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/general.js b/x-pack/plugins/index_lifecycle_management/public/application/store/selectors/general.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/general.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/selectors/general.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/index.js b/x-pack/plugins/index_lifecycle_management/public/application/store/selectors/index.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/index.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/selectors/index.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/lifecycle.js b/x-pack/plugins/index_lifecycle_management/public/application/store/selectors/lifecycle.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/lifecycle.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/selectors/lifecycle.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/nodes.js b/x-pack/plugins/index_lifecycle_management/public/application/store/selectors/nodes.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/nodes.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/selectors/nodes.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/policies.js b/x-pack/plugins/index_lifecycle_management/public/application/store/selectors/policies.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/selectors/policies.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/selectors/policies.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/store.js b/x-pack/plugins/index_lifecycle_management/public/application/store/store.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/store/store.js
rename to x-pack/plugins/index_lifecycle_management/public/application/store/store.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/add_lifecycle_confirm_modal.js b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.js
similarity index 97%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/add_lifecycle_confirm_modal.js
rename to x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.js
index 5b8f2d197daf4..143895150172d 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/add_lifecycle_confirm_modal.js
+++ b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.js
@@ -23,7 +23,7 @@ import {
   EuiModalHeaderTitle,
 } from '@elastic/eui';
 
-import { BASE_PATH } from '../../../../common/constants';
+import { BASE_PATH } from '../../../common/constants';
 import { loadPolicies, addLifecyclePolicyToIndex } from '../../application/services/api';
 import { showApiError } from '../../application/services/api_errors';
 import { toasts } from '../../application/services/notification';
@@ -38,7 +38,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
     };
   }
   addPolicy = async () => {
-    const { indexName, httpClient, closeModal, reloadIndices } = this.props;
+    const { indexName, closeModal, reloadIndices } = this.props;
     const { selectedPolicyName, selectedAlias } = this.state;
     if (!selectedPolicyName) {
       this.setState({
@@ -55,7 +55,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
         policyName: selectedPolicyName,
         alias: selectedAlias,
       };
-      await addLifecyclePolicyToIndex(body, httpClient);
+      await addLifecyclePolicyToIndex(body);
       closeModal();
       toasts.addSuccess(
         i18n.translate(
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/index_lifecycle_summary.js b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/index_lifecycle_summary.js
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/index_lifecycle_summary.js
rename to x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/index_lifecycle_summary.js
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/remove_lifecycle_confirm_modal.js b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.js
similarity index 96%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/remove_lifecycle_confirm_modal.js
rename to x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.js
index 0ba5ed1720084..4e0d2383c7d79 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/components/remove_lifecycle_confirm_modal.js
+++ b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.js
@@ -24,10 +24,10 @@ export class RemoveLifecyclePolicyConfirmModal extends Component {
   }
 
   removePolicy = async () => {
-    const { indexNames, httpClient, closeModal, reloadIndices } = this.props;
+    const { indexNames, closeModal, reloadIndices } = this.props;
 
     try {
-      await removeLifecycleForIndex(indexNames, httpClient);
+      await removeLifecycleForIndex(indexNames);
       closeModal();
       toasts.addSuccess(
         i18n.translate(
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.d.ts b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/index.d.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.d.ts
rename to x-pack/plugins/index_lifecycle_management/public/extend_index_management/index.d.ts
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/index.js
similarity index 80%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js
rename to x-pack/plugins/index_lifecycle_management/public/extend_index_management/index.js
index 69658d31695bc..40ff04408002f 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js
+++ b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/index.js
@@ -9,8 +9,6 @@ import { get, every, any } from 'lodash';
 import { i18n } from '@kbn/i18n';
 import { EuiSearchBar } from '@elastic/eui';
 
-import { init as initUiMetric } from '../application/services/ui_metric';
-import { init as initNotification } from '../application/services/notification';
 import { retryLifecycleForIndex } from '../application/services/api';
 import { IndexLifecycleSummary } from './components/index_lifecycle_summary';
 import { AddLifecyclePolicyConfirmModal } from './components/add_lifecycle_confirm_modal';
@@ -18,21 +16,7 @@ import { RemoveLifecyclePolicyConfirmModal } from './components/remove_lifecycle
 
 const stepPath = 'ilm.step';
 
-export const retryLifecycleActionExtension = ({
-  indices,
-  usageCollection,
-  toasts,
-  fatalErrors,
-}) => {
-  // These are hacks that we can remove once the New Platform migration is done. They're needed here
-  // because API requests and API errors require them.
-  const getLegacyReporter = appName => (type, name) => {
-    usageCollection.reportUiStats(appName, type, name);
-  };
-
-  initUiMetric(getLegacyReporter);
-  initNotification(toasts, fatalErrors);
-
+export const retryLifecycleActionExtension = ({ indices }) => {
   const allHaveErrors = every(indices, index => {
     return index.ilm && index.ilm.failed_step;
   });
@@ -57,19 +41,7 @@ export const retryLifecycleActionExtension = ({
   };
 };
 
-export const removeLifecyclePolicyActionExtension = ({
-  indices,
-  reloadIndices,
-  createUiStatsReporter,
-  toasts,
-  fatalErrors,
-  httpClient,
-}) => {
-  // These are hacks that we can remove once the New Platform migration is done. They're needed here
-  // because API requests and API errors require them.
-  initUiMetric(createUiStatsReporter);
-  initNotification(toasts, fatalErrors);
-
+export const removeLifecyclePolicyActionExtension = ({ indices, reloadIndices }) => {
   const allHaveIlm = every(indices, index => {
     return index.ilm && index.ilm.managed;
   });
@@ -83,8 +55,6 @@ export const removeLifecyclePolicyActionExtension = ({
         <RemoveLifecyclePolicyConfirmModal
           indexNames={indexNames}
           closeModal={closeModal}
-          httpClient={httpClient}
-          toasts={toasts}
           reloadIndices={reloadIndices}
         />
       );
@@ -97,19 +67,7 @@ export const removeLifecyclePolicyActionExtension = ({
   };
 };
 
-export const addLifecyclePolicyActionExtension = ({
-  indices,
-  reloadIndices,
-  createUiStatsReporter,
-  toasts,
-  fatalErrors,
-  httpClient,
-}) => {
-  // These are hacks that we can remove once the New Platform migration is done. They're needed here
-  // because API requests and API errors require them.
-  initUiMetric(createUiStatsReporter);
-  initNotification(toasts, fatalErrors);
-
+export const addLifecyclePolicyActionExtension = ({ indices, reloadIndices }) => {
   if (indices.length !== 1) {
     return null;
   }
@@ -126,8 +84,6 @@ export const addLifecyclePolicyActionExtension = ({
         <AddLifecyclePolicyConfirmModal
           indexName={indexName}
           closeModal={closeModal}
-          httpClient={httpClient}
-          toasts={toasts}
           index={index}
           reloadIndices={reloadIndices}
         />
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/index.ts b/x-pack/plugins/index_lifecycle_management/public/index.ts
similarity index 58%
rename from x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/index.ts
rename to x-pack/plugins/index_lifecycle_management/public/index.ts
index 1af0b697a9283..586763188a54b 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/index.ts
@@ -4,7 +4,11 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { PluginInitializerContext } from 'src/core/public';
+import { PluginInitializerContext } from 'kibana/public';
+
 import { IndexLifecycleManagementPlugin } from './plugin';
 
-export const createPlugin = (ctx: PluginInitializerContext) => new IndexLifecycleManagementPlugin();
+/** @public */
+export const plugin = (initializerContext: PluginInitializerContext) => {
+  return new IndexLifecycleManagementPlugin(initializerContext);
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx
new file mode 100644
index 0000000000000..ca93646e20fcf
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { CoreSetup, PluginInitializerContext } from 'src/core/public';
+
+import { PLUGIN } from '../common/constants';
+import { init as initHttp } from './application/services/http';
+import { init as initDocumentation } from './application/services/documentation';
+import { init as initUiMetric } from './application/services/ui_metric';
+import { init as initNotification } from './application/services/notification';
+import { addAllExtensions } from './extend_index_management';
+import { PluginsDependencies, ClientConfigType } from './types';
+
+export class IndexLifecycleManagementPlugin {
+  constructor(private readonly initializerContext: PluginInitializerContext) {}
+
+  public setup(coreSetup: CoreSetup, plugins: PluginsDependencies) {
+    const {
+      ui: { enabled: isIndexLifecycleManagementUiEnabled },
+    } = this.initializerContext.config.get<ClientConfigType>();
+
+    if (isIndexLifecycleManagementUiEnabled) {
+      const {
+        http,
+        notifications: { toasts },
+        fatalErrors,
+        getStartServices,
+      } = coreSetup;
+
+      const { usageCollection, management, indexManagement } = plugins;
+
+      // Initialize services even if the app isn't mounted, because they're used by index management extensions.
+      initHttp(http);
+      initUiMetric(usageCollection);
+      initNotification(toasts, fatalErrors);
+
+      management.sections.getSection('elasticsearch')!.registerApp({
+        id: PLUGIN.ID,
+        title: PLUGIN.TITLE,
+        order: 2,
+        mount: async ({ element }) => {
+          const [coreStart] = await getStartServices();
+          const {
+            i18n: { Context: I18nContext },
+            docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
+          } = coreStart;
+
+          // Initialize additional services.
+          initDocumentation(
+            `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/`
+          );
+
+          const { renderApp } = await import('./application');
+          return renderApp(element, I18nContext);
+        },
+      });
+
+      if (indexManagement) {
+        addAllExtensions(indexManagement.extensionsService);
+      }
+    }
+  }
+
+  public start() {}
+  public stop() {}
+}
diff --git a/x-pack/plugins/index_lifecycle_management/public/types.ts b/x-pack/plugins/index_lifecycle_management/public/types.ts
new file mode 100644
index 0000000000000..f9e0abae56cb4
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/types.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public';
+import { ManagementSetup } from '../../../../src/plugins/management/public';
+import { IndexManagementPluginSetup } from '../../index_management/public';
+
+export interface PluginsDependencies {
+  usageCollection: UsageCollectionSetup;
+  management: ManagementSetup;
+  indexManagement?: IndexManagementPluginSetup;
+}
+
+export interface ClientConfigType {
+  ui: {
+    enabled: boolean;
+  };
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/config.ts b/x-pack/plugins/index_lifecycle_management/server/config.ts
new file mode 100644
index 0000000000000..9728e31a8a148
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/config.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema, TypeOf } from '@kbn/config-schema';
+
+export const configSchema = schema.object({
+  enabled: schema.boolean({ defaultValue: true }),
+  ui: schema.object({
+    enabled: schema.boolean({ defaultValue: true }),
+  }),
+  // Cloud requires the ability to hide internal node attributes from users.
+  filteredNodeAttributes: schema.arrayOf(schema.string(), { defaultValue: [] }),
+});
+
+export type IndexLifecycleManagementConfig = TypeOf<typeof configSchema>;
diff --git a/x-pack/plugins/index_lifecycle_management/server/index.ts b/x-pack/plugins/index_lifecycle_management/server/index.ts
new file mode 100644
index 0000000000000..8a5f0fe19f9b0
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { PluginInitializerContext, PluginConfigDescriptor } from 'kibana/server';
+import { IndexLifecycleManagementServerPlugin } from './plugin';
+import { configSchema, IndexLifecycleManagementConfig } from './config';
+
+export const plugin = (ctx: PluginInitializerContext) =>
+  new IndexLifecycleManagementServerPlugin(ctx);
+
+export const config: PluginConfigDescriptor<IndexLifecycleManagementConfig> = {
+  schema: configSchema,
+  exposeToBrowser: {
+    ui: true,
+  },
+};
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/is_es_error/is_es_error.ts b/x-pack/plugins/index_lifecycle_management/server/lib/is_es_error.ts
similarity index 100%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/lib/is_es_error/is_es_error.ts
rename to x-pack/plugins/index_lifecycle_management/server/lib/is_es_error.ts
diff --git a/x-pack/plugins/index_lifecycle_management/server/plugin.ts b/x-pack/plugins/index_lifecycle_management/server/plugin.ts
new file mode 100644
index 0000000000000..48c50f9a48ee5
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/plugin.ts
@@ -0,0 +1,86 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { Observable } from 'rxjs';
+import { first } from 'rxjs/operators';
+import { i18n } from '@kbn/i18n';
+import { CoreSetup, Plugin, Logger, PluginInitializerContext, APICaller } from 'src/core/server';
+
+import { PLUGIN } from '../common/constants';
+import { Dependencies } from './types';
+import { registerApiRoutes } from './routes';
+import { License } from './services';
+import { IndexLifecycleManagementConfig } from './config';
+import { isEsError } from './lib/is_es_error';
+
+const indexLifecycleDataEnricher = async (indicesList: any, callAsCurrentUser: APICaller) => {
+  if (!indicesList || !indicesList.length) {
+    return;
+  }
+
+  const params = {
+    path: '/*/_ilm/explain',
+    method: 'GET',
+  };
+
+  const { indices: ilmIndicesData } = await callAsCurrentUser('transport.request', params);
+
+  return indicesList.map((index: any): any => {
+    return {
+      ...index,
+      ilm: { ...(ilmIndicesData[index.name] || {}) },
+    };
+  });
+};
+
+export class IndexLifecycleManagementServerPlugin implements Plugin<void, void, any, any> {
+  private readonly config$: Observable<IndexLifecycleManagementConfig>;
+  private readonly license: License;
+  private readonly logger: Logger;
+
+  constructor(initializerContext: PluginInitializerContext) {
+    this.logger = initializerContext.logger.get();
+    this.config$ = initializerContext.config.create();
+    this.license = new License();
+  }
+
+  async setup({ http }: CoreSetup, { licensing, indexManagement }: Dependencies): Promise<void> {
+    const router = http.createRouter();
+    const config = await this.config$.pipe(first()).toPromise();
+
+    this.license.setup(
+      {
+        pluginId: PLUGIN.ID,
+        minimumLicenseType: PLUGIN.minimumLicenseType,
+        defaultErrorMessage: i18n.translate('xpack.indexLifecycleMgmt.licenseCheckErrorMessage', {
+          defaultMessage: 'License check failed',
+        }),
+      },
+      {
+        licensing,
+        logger: this.logger,
+      }
+    );
+
+    registerApiRoutes({
+      router,
+      config,
+      license: this.license,
+      lib: {
+        isEsError,
+      },
+    });
+
+    if (config.ui.enabled) {
+      if (indexManagement.indexDataEnricher) {
+        indexManagement.indexDataEnricher.add(indexLifecycleDataEnricher);
+      }
+    }
+  }
+
+  start() {}
+  stop() {}
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_index_routes.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/index.ts
similarity index 65%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_index_routes.ts
rename to x-pack/plugins/index_lifecycle_management/server/routes/api/index/index.ts
index 74eb1a86a93ba..abe00af74b63a 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/index/register_index_routes.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/index.ts
@@ -4,12 +4,13 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { RouteDependencies } from '../../../types';
 import { registerRetryRoute } from './register_retry_route';
 import { registerRemoveRoute } from './register_remove_route';
 import { registerAddPolicyRoute } from './register_add_policy_route';
 
-export function registerIndexRoutes(server: any) {
-  registerRetryRoute(server);
-  registerRemoveRoute(server);
-  registerAddPolicyRoute(server);
+export function registerIndexRoutes(dependencies: RouteDependencies) {
+  registerRetryRoute(dependencies);
+  registerRemoveRoute(dependencies);
+  registerAddPolicyRoute(dependencies);
 }
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts
new file mode 100644
index 0000000000000..9627f6399eaaf
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_add_policy_route.ts
@@ -0,0 +1,66 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+async function addLifecyclePolicy(
+  callAsCurrentUser: APICaller,
+  indexName: string,
+  policyName: string,
+  alias: string
+) {
+  const params = {
+    method: 'PUT',
+    path: `/${encodeURIComponent(indexName)}/_settings`,
+    body: {
+      lifecycle: {
+        name: policyName,
+        rollover_alias: alias,
+      },
+    },
+  };
+
+  return callAsCurrentUser('transport.request', params);
+}
+
+const bodySchema = schema.object({
+  indexName: schema.string(),
+  policyName: schema.string(),
+  alias: schema.maybe(schema.string()),
+});
+
+export function registerAddPolicyRoute({ router, license, lib }: RouteDependencies) {
+  router.post(
+    { path: addBasePath('/index/add'), validate: { body: bodySchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const body = request.body as typeof bodySchema.type;
+      const { indexName, policyName, alias = '' } = body;
+
+      try {
+        await addLifecyclePolicy(
+          context.core.elasticsearch.dataClient.callAsCurrentUser,
+          indexName,
+          policyName,
+          alias
+        );
+        return response.ok();
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts
new file mode 100644
index 0000000000000..8ec94a8591785
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_remove_route.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+async function removeLifecycle(callAsCurrentUser: APICaller, indexNames: string[]) {
+  const responses = [];
+  for (let i = 0; i < indexNames.length; i++) {
+    const indexName = indexNames[i];
+    const params = {
+      method: 'POST',
+      path: `/${encodeURIComponent(indexName)}/_ilm/remove`,
+      ignore: [404],
+    };
+
+    responses.push(callAsCurrentUser('transport.request', params));
+  }
+  return Promise.all(responses);
+}
+
+const bodySchema = schema.object({
+  indexNames: schema.arrayOf(schema.string()),
+});
+
+export function registerRemoveRoute({ router, license, lib }: RouteDependencies) {
+  router.post(
+    { path: addBasePath('/index/remove'), validate: { body: bodySchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const body = request.body as typeof bodySchema.type;
+      const { indexNames } = body;
+
+      try {
+        await removeLifecycle(context.core.elasticsearch.dataClient.callAsCurrentUser, indexNames);
+        return response.ok();
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts
new file mode 100644
index 0000000000000..1e2d621cab173
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/index/register_retry_route.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+async function retryLifecycle(callAsCurrentUser: APICaller, indexNames: string[]) {
+  const responses = [];
+  for (let i = 0; i < indexNames.length; i++) {
+    const indexName = indexNames[i];
+    const params = {
+      method: 'POST',
+      path: `/${encodeURIComponent(indexName)}/_ilm/retry`,
+      ignore: [404],
+    };
+
+    responses.push(callAsCurrentUser('transport.request', params));
+  }
+  return Promise.all(responses);
+}
+
+const bodySchema = schema.object({
+  indexNames: schema.arrayOf(schema.string()),
+});
+
+export function registerRetryRoute({ router, license, lib }: RouteDependencies) {
+  router.post(
+    { path: addBasePath('/index/retry'), validate: { body: bodySchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const body = request.body as typeof bodySchema.type;
+      const { indexNames } = body;
+
+      try {
+        await retryLifecycle(context.core.elasticsearch.dataClient.callAsCurrentUser, indexNames);
+        return response.ok();
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_nodes_routes.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts
similarity index 65%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_nodes_routes.ts
rename to x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts
index 4486d97038657..bde56f0318bbd 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/nodes/register_nodes_routes.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/index.ts
@@ -4,10 +4,11 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { RouteDependencies } from '../../../types';
 import { registerListRoute } from './register_list_route';
 import { registerDetailsRoute } from './register_details_route';
 
-export function registerNodesRoutes(server: any) {
-  registerListRoute(server);
-  registerDetailsRoute(server);
+export function registerNodesRoutes(dependencies: RouteDependencies) {
+  registerListRoute(dependencies);
+  registerDetailsRoute(dependencies);
 }
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts
new file mode 100644
index 0000000000000..6ff1f147e7ea7
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_details_route.ts
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+function findMatchingNodes(stats: any, nodeAttrs: string): any {
+  return Object.entries(stats.nodes).reduce((accum: any[], [nodeId, nodeStats]: [any, any]) => {
+    const attributes = nodeStats.attributes || {};
+    for (const [key, value] of Object.entries(attributes)) {
+      if (`${key}:${value}` === nodeAttrs) {
+        accum.push({
+          nodeId,
+          stats: nodeStats,
+        });
+        break;
+      }
+    }
+    return accum;
+  }, []);
+}
+
+async function fetchNodeStats(callAsCurrentUser: APICaller): Promise<any> {
+  const params = {
+    format: 'json',
+  };
+
+  return await callAsCurrentUser('nodes.stats', params);
+}
+
+const paramsSchema = schema.object({
+  nodeAttrs: schema.string(),
+});
+
+export function registerDetailsRoute({ router, license, lib }: RouteDependencies) {
+  router.get(
+    { path: addBasePath('/nodes/{nodeAttrs}/details'), validate: { params: paramsSchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const params = request.params as typeof paramsSchema.type;
+      const { nodeAttrs } = params;
+
+      try {
+        const stats = await fetchNodeStats(context.core.elasticsearch.dataClient.callAsCurrentUser);
+        const okResponse = { body: findMatchingNodes(stats, nodeAttrs) };
+        return response.ok(okResponse);
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts
new file mode 100644
index 0000000000000..73d85c78d3b11
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+function convertStatsIntoList(stats: any, disallowedNodeAttributes: string[]): any {
+  return Object.entries(stats.nodes).reduce((accum: any, [nodeId, nodeStats]: [any, any]) => {
+    const attributes = nodeStats.attributes || {};
+    for (const [key, value] of Object.entries(attributes)) {
+      const isNodeAttributeAllowed = !disallowedNodeAttributes.includes(key);
+      if (isNodeAttributeAllowed) {
+        const attributeString = `${key}:${value}`;
+        accum[attributeString] = accum[attributeString] || [];
+        accum[attributeString].push(nodeId);
+      }
+    }
+    return accum;
+  }, {});
+}
+
+async function fetchNodeStats(callAsCurrentUser: APICaller): Promise<any> {
+  const params = {
+    format: 'json',
+  };
+
+  return await callAsCurrentUser('nodes.stats', params);
+}
+
+export function registerListRoute({ router, config, license, lib }: RouteDependencies) {
+  const { filteredNodeAttributes } = config;
+
+  const NODE_ATTRS_KEYS_TO_IGNORE: string[] = [
+    'ml.enabled',
+    'ml.machine_memory',
+    'ml.max_open_jobs',
+    // Used by ML to identify nodes that have transform enabled:
+    // https://github.com/elastic/elasticsearch/pull/52712/files#diff-225cc2c1291b4c60a8c3412a619094e1R147
+    'transform.node',
+    'xpack.installed',
+  ];
+
+  const disallowedNodeAttributes = [...NODE_ATTRS_KEYS_TO_IGNORE, ...filteredNodeAttributes];
+
+  router.get(
+    { path: addBasePath('/nodes/list'), validate: false },
+    license.guardApiRoute(async (context, request, response) => {
+      try {
+        const stats = await fetchNodeStats(context.core.elasticsearch.dataClient.callAsCurrentUser);
+        const okResponse = { body: convertStatsIntoList(stats, disallowedNodeAttributes) };
+        return response.ok(okResponse);
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_policies_routes.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/index.ts
similarity index 64%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_policies_routes.ts
rename to x-pack/plugins/index_lifecycle_management/server/routes/api/policies/index.ts
index 279b016da178f..c30dc04c61169 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/policies/register_policies_routes.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/index.ts
@@ -4,12 +4,13 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { RouteDependencies } from '../../../types';
 import { registerFetchRoute } from './register_fetch_route';
 import { registerCreateRoute } from './register_create_route';
 import { registerDeleteRoute } from './register_delete_route';
 
-export function registerPoliciesRoutes(server: any) {
-  registerFetchRoute(server);
-  registerCreateRoute(server);
-  registerDeleteRoute(server);
+export function registerPoliciesRoutes(dependencies: RouteDependencies) {
+  registerFetchRoute(dependencies);
+  registerCreateRoute(dependencies);
+  registerDeleteRoute(dependencies);
 }
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
new file mode 100644
index 0000000000000..a9c6bab58fdd9
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
@@ -0,0 +1,145 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+async function createPolicy(callAsCurrentUser: APICaller, name: string, phases: any): Promise<any> {
+  const body = {
+    policy: {
+      phases,
+    },
+  };
+  const params = {
+    method: 'PUT',
+    path: `/_ilm/policy/${encodeURIComponent(name)}`,
+    ignore: [404],
+    body,
+  };
+
+  return await callAsCurrentUser('transport.request', params);
+}
+
+const minAgeSchema = schema.maybe(schema.string());
+
+const setPrioritySchema = schema.maybe(
+  schema.object({
+    priority: schema.number(),
+  })
+);
+
+const unfollowSchema = schema.maybe(schema.object({})); // Unfollow has no options
+
+const allocateNodeSchema = schema.maybe(schema.recordOf(schema.string(), schema.string()));
+const allocateSchema = schema.maybe(
+  schema.object({
+    number_of_replicas: schema.maybe(schema.number()),
+    include: allocateNodeSchema,
+    exclude: allocateNodeSchema,
+    require: allocateNodeSchema,
+  })
+);
+
+const hotPhaseSchema = schema.object({
+  min_age: minAgeSchema,
+  actions: schema.object({
+    set_priority: setPrioritySchema,
+    unfollow: unfollowSchema,
+    rollover: schema.maybe(
+      schema.object({
+        max_age: schema.maybe(schema.string()),
+        max_size: schema.maybe(schema.string()),
+        max_docs: schema.maybe(schema.number()),
+      })
+    ),
+  }),
+});
+
+const warmPhaseSchema = schema.maybe(
+  schema.object({
+    min_age: minAgeSchema,
+    actions: schema.object({
+      set_priority: setPrioritySchema,
+      unfollow: unfollowSchema,
+      read_only: schema.maybe(schema.object({})), // Readonly has no options
+      allocate: allocateSchema,
+      shrink: schema.maybe(
+        schema.object({
+          number_of_shards: schema.number(),
+        })
+      ),
+      forcemerge: schema.maybe(
+        schema.object({
+          max_num_segments: schema.number(),
+        })
+      ),
+    }),
+  })
+);
+
+const coldPhaseSchema = schema.maybe(
+  schema.object({
+    min_age: minAgeSchema,
+    actions: schema.object({
+      set_priority: setPrioritySchema,
+      unfollow: unfollowSchema,
+      allocate: allocateSchema,
+      freeze: schema.maybe(schema.object({})), // Freeze has no options
+    }),
+  })
+);
+
+const deletePhaseSchema = schema.maybe(
+  schema.object({
+    min_age: minAgeSchema,
+    actions: schema.object({
+      wait_for_snapshot: schema.maybe(
+        schema.object({
+          policy: schema.string(),
+        })
+      ),
+      delete: schema.maybe(schema.object({})), // Delete has no options
+    }),
+  })
+);
+
+// Per https://www.elastic.co/guide/en/elasticsearch/reference/current/_actions.html
+const bodySchema = schema.object({
+  name: schema.string(),
+  phases: schema.object({
+    hot: hotPhaseSchema,
+    warm: warmPhaseSchema,
+    cold: coldPhaseSchema,
+    delete: deletePhaseSchema,
+  }),
+});
+
+export function registerCreateRoute({ router, license, lib }: RouteDependencies) {
+  router.post(
+    { path: addBasePath('/policies'), validate: { body: bodySchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const body = request.body as typeof bodySchema.type;
+      const { name, phases } = body;
+
+      try {
+        await createPolicy(context.core.elasticsearch.dataClient.callAsCurrentUser, name, phases);
+        return response.ok();
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts
new file mode 100644
index 0000000000000..e08297f4d7bc4
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+async function deletePolicies(callAsCurrentUser: APICaller, policyNames: string): Promise<any> {
+  const params = {
+    method: 'DELETE',
+    path: `/_ilm/policy/${encodeURIComponent(policyNames)}`,
+    // we allow 404 since they may have no policies
+    ignore: [404],
+  };
+
+  return await callAsCurrentUser('transport.request', params);
+}
+
+const paramsSchema = schema.object({
+  policyNames: schema.string(),
+});
+
+export function registerDeleteRoute({ router, license, lib }: RouteDependencies) {
+  router.delete(
+    { path: addBasePath('/policies/{policyNames}'), validate: { params: paramsSchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const params = request.params as typeof paramsSchema.type;
+      const { policyNames } = params;
+
+      try {
+        await deletePolicies(context.core.elasticsearch.dataClient.callAsCurrentUser, policyNames);
+        return response.ok();
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts
new file mode 100644
index 0000000000000..294b7c4c65cba
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts
@@ -0,0 +1,90 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+function formatPolicies(policiesMap: any): any {
+  if (policiesMap.status === 404) {
+    return [];
+  }
+
+  return Object.keys(policiesMap).reduce((accum: any[], lifecycleName: string) => {
+    const policyEntry = policiesMap[lifecycleName];
+    accum.push({
+      ...policyEntry,
+      name: lifecycleName,
+    });
+    return accum;
+  }, []);
+}
+
+async function fetchPolicies(callAsCurrentUser: APICaller): Promise<any> {
+  const params = {
+    method: 'GET',
+    path: '/_ilm/policy',
+    // we allow 404 since they may have no policies
+    ignore: [404],
+  };
+
+  return await callAsCurrentUser('transport.request', params);
+}
+
+async function addLinkedIndices(callAsCurrentUser: APICaller, policiesMap: any) {
+  if (policiesMap.status === 404) {
+    return policiesMap;
+  }
+  const params = {
+    method: 'GET',
+    path: '/*/_ilm/explain',
+    // we allow 404 since they may have no policies
+    ignore: [404],
+  };
+
+  const policyExplanation: any = await callAsCurrentUser('transport.request', params);
+  Object.entries(policyExplanation.indices).forEach(([indexName, { policy }]: [string, any]) => {
+    if (policy && policiesMap[policy]) {
+      policiesMap[policy].linkedIndices = policiesMap[policy].linkedIndices || [];
+      policiesMap[policy].linkedIndices.push(indexName);
+    }
+  });
+}
+
+const querySchema = schema.object({
+  withIndices: schema.boolean({ defaultValue: false }),
+});
+
+export function registerFetchRoute({ router, license, lib }: RouteDependencies) {
+  router.get(
+    { path: addBasePath('/policies'), validate: { query: querySchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const query = request.query as typeof querySchema.type;
+      const { withIndices } = query;
+      const { callAsCurrentUser } = context.core.elasticsearch.dataClient;
+
+      try {
+        const policiesMap = await fetchPolicies(callAsCurrentUser);
+        if (withIndices) {
+          await addLinkedIndices(callAsCurrentUser, policiesMap);
+        }
+        const okResponse = { body: formatPolicies(policiesMap) };
+        return response.ok(okResponse);
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_templates_routes.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/index.ts
similarity index 64%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_templates_routes.ts
rename to x-pack/plugins/index_lifecycle_management/server/routes/api/templates/index.ts
index 424b2d36b1ba2..a2d885c3170b9 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_templates_routes.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/index.ts
@@ -4,12 +4,11 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import { RouteDependencies } from '../../../types';
 import { registerFetchRoute } from './register_fetch_route';
-import { registerGetRoute } from './register_get_route';
 import { registerAddPolicyRoute } from './register_add_policy_route';
 
-export function registerTemplatesRoutes(server: any) {
-  registerFetchRoute(server);
-  registerGetRoute(server);
-  registerAddPolicyRoute(server);
+export function registerTemplatesRoutes(dependencies: RouteDependencies) {
+  registerFetchRoute(dependencies);
+  registerAddPolicyRoute(dependencies);
 }
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts
new file mode 100644
index 0000000000000..0da8535f8d4ec
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts
@@ -0,0 +1,81 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { merge } from 'lodash';
+import { schema } from '@kbn/config-schema';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
+
+async function getIndexTemplate(callAsCurrentUser: APICaller, templateName: string): Promise<any> {
+  const response = await callAsCurrentUser('indices.getTemplate', { name: templateName });
+  return response[templateName];
+}
+
+async function updateIndexTemplate(
+  callAsCurrentUser: APICaller,
+  templateName: string,
+  policyName: string,
+  aliasName?: string
+): Promise<any> {
+  // Fetch existing template
+  const template = await getIndexTemplate(callAsCurrentUser, templateName);
+  merge(template, {
+    settings: {
+      index: {
+        lifecycle: {
+          name: policyName,
+          rollover_alias: aliasName,
+        },
+      },
+    },
+  });
+
+  const params = {
+    method: 'PUT',
+    path: `/_template/${encodeURIComponent(templateName)}`,
+    ignore: [404],
+    body: template,
+  };
+
+  return await callAsCurrentUser('transport.request', params);
+}
+
+const bodySchema = schema.object({
+  templateName: schema.string(),
+  policyName: schema.string(),
+  aliasName: schema.maybe(schema.string()),
+});
+
+export function registerAddPolicyRoute({ router, license, lib }: RouteDependencies) {
+  router.post(
+    { path: addBasePath('/template'), validate: { body: bodySchema } },
+    license.guardApiRoute(async (context, request, response) => {
+      const body = request.body as typeof bodySchema.type;
+      const { templateName, policyName, aliasName } = body;
+
+      try {
+        await updateIndexTemplate(
+          context.core.elasticsearch.dataClient.callAsCurrentUser,
+          templateName,
+          policyName,
+          aliasName
+        );
+        return response.ok();
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
+        }
+        // Case: default
+        return response.internalError({ body: e });
+      }
+    })
+  );
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts
similarity index 63%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts
rename to x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts
index fd58f471d69bb..a2dc67cb77afe 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_fetch_route.ts
@@ -4,10 +4,10 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
-import { isEsError } from '../../../lib/is_es_error';
-import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
+import { APICaller } from 'src/core/server';
+
+import { RouteDependencies } from '../../../types';
+import { addBasePath } from '../../../services';
 
 /**
  * We don't want to output system template (whose name starts with a ".") which don't
@@ -49,7 +49,7 @@ function filterAndFormatTemplates(templates: any): any {
   return formattedTemplates;
 }
 
-async function fetchTemplates(callWithRequest: any): Promise<any> {
+async function fetchTemplates(callAsCurrentUser: APICaller): Promise<any> {
   const params = {
     method: 'GET',
     path: '/_template',
@@ -57,30 +57,29 @@ async function fetchTemplates(callWithRequest: any): Promise<any> {
     ignore: [404],
   };
 
-  return await callWithRequest('transport.request', params);
+  return await callAsCurrentUser('transport.request', params);
 }
-export function registerFetchRoute(server: any) {
-  const licensePreRouting = licensePreRoutingFactory(server);
-
-  server.route({
-    path: '/api/index_lifecycle_management/templates',
-    method: 'GET',
-    handler: async (request: any) => {
-      const callWithRequest = callWithRequestFactory(server, request);
 
+export function registerFetchRoute({ router, license, lib }: RouteDependencies) {
+  router.get(
+    { path: addBasePath('/templates'), validate: false },
+    license.guardApiRoute(async (context, request, response) => {
       try {
-        const templates = await fetchTemplates(callWithRequest);
-        return filterAndFormatTemplates(templates);
-      } catch (err) {
-        if (isEsError(err)) {
-          return wrapEsError(err);
+        const templates = await fetchTemplates(
+          context.core.elasticsearch.dataClient.callAsCurrentUser
+        );
+        const okResponse = { body: filterAndFormatTemplates(templates) };
+        return response.ok(okResponse);
+      } catch (e) {
+        if (lib.isEsError(e)) {
+          return response.customError({
+            statusCode: e.statusCode,
+            body: e,
+          });
         }
-
-        return wrapUnknownError(err);
+        // Case: default
+        return response.internalError({ body: e });
       }
-    },
-    config: {
-      pre: [licensePreRouting],
-    },
-  });
+    })
+  );
 }
diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/index.ts b/x-pack/plugins/index_lifecycle_management/server/routes/index.ts
new file mode 100644
index 0000000000000..35996721854c6
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/routes/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { RouteDependencies } from '../types';
+
+import { registerIndexRoutes } from './api/index';
+import { registerNodesRoutes } from './api/nodes';
+import { registerPoliciesRoutes } from './api/policies';
+import { registerTemplatesRoutes } from './api/templates';
+
+export function registerApiRoutes(dependencies: RouteDependencies) {
+  registerIndexRoutes(dependencies);
+  registerNodesRoutes(dependencies);
+  registerPoliciesRoutes(dependencies);
+  registerTemplatesRoutes(dependencies);
+}
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/index.ts b/x-pack/plugins/index_lifecycle_management/server/services/add_base_path.ts
similarity index 64%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/index.ts
rename to x-pack/plugins/index_lifecycle_management/server/services/add_base_path.ts
index f2c070fd44b6e..3f3dd131df7c7 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/services/add_base_path.ts
@@ -4,4 +4,6 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-export { checkLicense } from './check_license';
+import { API_BASE_PATH } from '../../common/constants';
+
+export const addBasePath = (uri: string): string => `${API_BASE_PATH}${uri}`;
diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/index.ts b/x-pack/plugins/index_lifecycle_management/server/services/index.ts
similarity index 74%
rename from x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/index.ts
rename to x-pack/plugins/index_lifecycle_management/server/services/index.ts
index 0743e443955f4..d7b544b290c39 100644
--- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/license_pre_routing_factory/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/services/index.ts
@@ -4,4 +4,5 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-export { licensePreRoutingFactory } from './license_pre_routing_factory';
+export { License } from './license';
+export { addBasePath } from './add_base_path';
diff --git a/x-pack/plugins/index_lifecycle_management/server/services/license.ts b/x-pack/plugins/index_lifecycle_management/server/services/license.ts
new file mode 100644
index 0000000000000..31d3654c51e3e
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/services/license.ts
@@ -0,0 +1,82 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import { Logger } from 'src/core/server';
+import {
+  KibanaRequest,
+  KibanaResponseFactory,
+  RequestHandler,
+  RequestHandlerContext,
+} from 'kibana/server';
+
+import { LicensingPluginSetup } from '../../../licensing/server';
+import { LicenseType } from '../../../licensing/common/types';
+
+export interface LicenseStatus {
+  isValid: boolean;
+  message?: string;
+}
+
+interface SetupSettings {
+  pluginId: string;
+  minimumLicenseType: LicenseType;
+  defaultErrorMessage: string;
+}
+
+export class License {
+  private licenseStatus: LicenseStatus = {
+    isValid: false,
+    message: 'Invalid License',
+  };
+
+  setup(
+    { pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings,
+    { licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger }
+  ) {
+    licensing.license$.subscribe(license => {
+      const { state, message } = license.check(pluginId, minimumLicenseType);
+      const hasRequiredLicense = state === 'valid';
+
+      if (hasRequiredLicense) {
+        this.licenseStatus = { isValid: true };
+      } else {
+        this.licenseStatus = {
+          isValid: false,
+          message: message || defaultErrorMessage,
+        };
+        if (message) {
+          logger.info(message);
+        }
+      }
+    });
+  }
+
+  guardApiRoute(handler: RequestHandler) {
+    const license = this;
+
+    return function licenseCheck(
+      ctx: RequestHandlerContext,
+      request: KibanaRequest,
+      response: KibanaResponseFactory
+    ) {
+      const licenseStatus = license.getStatus();
+
+      if (!licenseStatus.isValid) {
+        return response.customError({
+          body: {
+            message: licenseStatus.message || '',
+          },
+          statusCode: 403,
+        });
+      }
+
+      return handler(ctx, request, response);
+    };
+  }
+
+  getStatus() {
+    return this.licenseStatus;
+  }
+}
diff --git a/x-pack/plugins/index_lifecycle_management/server/types.ts b/x-pack/plugins/index_lifecycle_management/server/types.ts
new file mode 100644
index 0000000000000..7f64c1a47197a
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/server/types.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { IRouter } from 'src/core/server';
+
+import { LicensingPluginSetup } from '../../licensing/server';
+import { IndexManagementPluginSetup } from '../../index_management/server';
+import { License } from './services';
+import { IndexLifecycleManagementConfig } from './config';
+import { isEsError } from './lib/is_es_error';
+
+export interface Dependencies {
+  licensing: LicensingPluginSetup;
+  indexManagement: IndexManagementPluginSetup;
+}
+
+export interface RouteDependencies {
+  router: IRouter;
+  config: IndexLifecycleManagementConfig;
+  license: License;
+  lib: {
+    isEsError: typeof isEsError;
+  };
+}
diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js
index 8f794ce1ed612..a351d39b123a8 100644
--- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js
+++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js
@@ -46,11 +46,7 @@ export class IndexActionsContextMenu extends Component {
   confirmAction = isActionConfirmed => {
     this.setState({ isActionConfirmed });
   };
-  panels({
-    core: { fatalErrors },
-    services: { extensionsService, httpService, notificationService },
-    plugins: { usageCollection },
-  }) {
+  panels({ services: { extensionsService } }) {
     const {
       closeIndices,
       openIndices,
@@ -218,15 +214,6 @@ export class IndexActionsContextMenu extends Component {
       const actionExtensionDefinition = actionExtension({
         indices,
         reloadIndices,
-        // These config options can be removed once the NP migration out of legacy is complete.
-        // They're needed for now because ILM's extensions make API calls which require these
-        // dependencies, but they're not available unless the app's "setup" lifecycle stage occurs.
-        // Within the old platform, "setup" only occurs once the user actually visits the app.
-        // Once ILM and IM have been moved out of legacy this hack won't be necessary.
-        usageCollection,
-        toasts: notificationService.toasts,
-        fatalErrors,
-        httpClient: httpService.httpClient,
       });
       if (actionExtensionDefinition) {
         const {
diff --git a/x-pack/plugins/index_management/public/index.ts b/x-pack/plugins/index_management/public/index.ts
index 6bb921ef648f3..7a76fff7f3ec6 100644
--- a/x-pack/plugins/index_management/public/index.ts
+++ b/x-pack/plugins/index_management/public/index.ts
@@ -4,13 +4,13 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 import './index.scss';
-import { IndexMgmtUIPlugin, IndexMgmtSetup } from './plugin';
+import { IndexMgmtUIPlugin, IndexManagementPluginSetup } from './plugin';
 
 /** @public */
 export const plugin = () => {
   return new IndexMgmtUIPlugin();
 };
 
-export { IndexMgmtSetup };
+export { IndexManagementPluginSetup };
 
 export { getIndexListUri } from './application/services/navigation';
diff --git a/x-pack/plugins/index_management/public/plugin.ts b/x-pack/plugins/index_management/public/plugin.ts
index 4aa06d286e3c4..f9e2a47170b3d 100644
--- a/x-pack/plugins/index_management/public/plugin.ts
+++ b/x-pack/plugins/index_management/public/plugin.ts
@@ -20,7 +20,7 @@ import { setUiMetricService } from './application/services/api';
 import { IndexMgmtMetricsType } from './types';
 import { ExtensionsService, ExtensionsSetup } from './services';
 
-export interface IndexMgmtSetup {
+export interface IndexManagementPluginSetup {
   extensionsService: ExtensionsSetup;
 }
 
@@ -40,7 +40,7 @@ export class IndexMgmtUIPlugin {
     setUiMetricService(this.uiMetricService);
   }
 
-  public setup(coreSetup: CoreSetup, plugins: PluginsDependencies): IndexMgmtSetup {
+  public setup(coreSetup: CoreSetup, plugins: PluginsDependencies): IndexManagementPluginSetup {
     const { http, notifications } = coreSetup;
     const { usageCollection, management } = plugins;
 
diff --git a/x-pack/plugins/index_management/server/index.ts b/x-pack/plugins/index_management/server/index.ts
index e4102711708cb..4d9409e4a516c 100644
--- a/x-pack/plugins/index_management/server/index.ts
+++ b/x-pack/plugins/index_management/server/index.ts
@@ -17,6 +17,6 @@ export const config = {
 
 /** @public */
 export { Dependencies } from './types';
-export { IndexMgmtSetup } from './plugin';
+export { IndexManagementPluginSetup } from './plugin';
 export { Index } from './types';
 export { IndexManagementConfig } from './config';
diff --git a/x-pack/plugins/index_management/server/plugin.ts b/x-pack/plugins/index_management/server/plugin.ts
index a0a9151cdb71f..e5bd7451b028f 100644
--- a/x-pack/plugins/index_management/server/plugin.ts
+++ b/x-pack/plugins/index_management/server/plugin.ts
@@ -12,13 +12,13 @@ import { ApiRoutes } from './routes';
 import { License, IndexDataEnricher } from './services';
 import { isEsError } from './lib/is_es_error';
 
-export interface IndexMgmtSetup {
+export interface IndexManagementPluginSetup {
   indexDataEnricher: {
     add: IndexDataEnricher['add'];
   };
 }
 
-export class IndexMgmtServerPlugin implements Plugin<IndexMgmtSetup, void, any, any> {
+export class IndexMgmtServerPlugin implements Plugin<IndexManagementPluginSetup, void, any, any> {
   private readonly apiRoutes: ApiRoutes;
   private readonly license: License;
   private readonly logger: Logger;
@@ -31,7 +31,7 @@ export class IndexMgmtServerPlugin implements Plugin<IndexMgmtSetup, void, any,
     this.indexDataEnricher = new IndexDataEnricher();
   }
 
-  setup({ http }: CoreSetup, { licensing }: Dependencies): IndexMgmtSetup {
+  setup({ http }: CoreSetup, { licensing }: Dependencies): IndexManagementPluginSetup {
     const router = http.createRouter();
 
     this.license.setup(
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 687834a683c4d..c07ec68e99b4f 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -7459,9 +7459,6 @@
     "xpack.indexLifecycleMgmt.activePhaseMessage": "アクティブ",
     "xpack.indexLifecycleMgmt.addLifecyclePolicyActionButtonLabel": "ライフサイクルポリシーを追加",
     "xpack.indexLifecycleMgmt.appTitle": "インデックスライフサイクルポリシー",
-    "xpack.indexLifecycleMgmt.checkLicense.errorExpiredMessage": "{licenseType} ライセンスが期限切れのため {pluginName} を使用できません。",
-    "xpack.indexLifecycleMgmt.checkLicense.errorUnavailableMessage": "現在ライセンス情報が利用できないため {pluginName} を使用できません。",
-    "xpack.indexLifecycleMgmt.checkLicense.errorUnsupportedMessage": "ご使用の {licenseType} ライセンスは {pluginName} をサポートしていません。ライセンスをアップグレードしてください。",
     "xpack.indexLifecycleMgmt.coldPhase.freezeIndexLabel": "インデックスを凍結",
     "xpack.indexLifecycleMgmt.coldPhase.numberOfReplicasLabel": "複製の数",
     "xpack.indexLifecycleMgmt.coldPhase.replicaCountHelpText": "デフォルトで、複製の数は同じままになります。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 58905787da8d5..de8aaa75632ee 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -7462,9 +7462,6 @@
     "xpack.indexLifecycleMgmt.activePhaseMessage": "有效",
     "xpack.indexLifecycleMgmt.addLifecyclePolicyActionButtonLabel": "添加生命周期策略",
     "xpack.indexLifecycleMgmt.appTitle": "索引生命周期策略",
-    "xpack.indexLifecycleMgmt.checkLicense.errorExpiredMessage": "您不能使用 {pluginName},因为您的 {licenseType} 许可已过期。",
-    "xpack.indexLifecycleMgmt.checkLicense.errorUnavailableMessage": "您不能使用 {pluginName},因为许可证信息当前不可用。",
-    "xpack.indexLifecycleMgmt.checkLicense.errorUnsupportedMessage": "您的 {licenseType} 许可证不支持 {pluginName}。请升级您的许可。",
     "xpack.indexLifecycleMgmt.coldPhase.freezeIndexLabel": "冻结索引",
     "xpack.indexLifecycleMgmt.coldPhase.numberOfReplicasLabel": "副本分片数目",
     "xpack.indexLifecycleMgmt.coldPhase.replicaCountHelpText": "默认情况下,副本分片数目仍一样。",
diff --git a/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.helpers.js b/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.helpers.js
index 8778ab5c807f5..257cca36b2ecf 100644
--- a/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.helpers.js
+++ b/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.helpers.js
@@ -9,8 +9,6 @@ import { API_BASE_PATH } from './constants';
 export const registerHelpers = ({ supertest }) => {
   const loadTemplates = () => supertest.get(`${API_BASE_PATH}/templates`);
 
-  const getTemplate = name => supertest.get(`${API_BASE_PATH}/templates/${name}`);
-
   const addPolicyToTemplate = (templateName, policyName, aliasName) =>
     supertest
       .post(`${API_BASE_PATH}/template`)
@@ -23,7 +21,6 @@ export const registerHelpers = ({ supertest }) => {
 
   return {
     loadTemplates,
-    getTemplate,
     addPolicyToTemplate,
   };
 };
diff --git a/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.js b/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.js
index 374577825cd94..d30c20527471b 100644
--- a/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.js
+++ b/x-pack/test/api_integration/apis/management/index_lifecycle_management/templates.js
@@ -16,7 +16,7 @@ export default function({ getService }) {
 
   const { createIndexTemplate, cleanUp: cleanUpEsResources } = initElasticsearchHelpers(es);
 
-  const { loadTemplates, getTemplate, addPolicyToTemplate } = registerTemplatesHelpers({
+  const { loadTemplates, addPolicyToTemplate } = registerTemplatesHelpers({
     supertest,
   });
 
@@ -48,18 +48,6 @@ export default function({ getService }) {
       });
     });
 
-    describe('get', () => {
-      it('should fetch a single template', async () => {
-        // Create a template with the ES client
-        const templateName = getRandomString();
-        const template = getTemplatePayload();
-        await createIndexTemplate(templateName, template);
-
-        const { body } = await getTemplate(templateName).expect(200);
-        expect(body.index_patterns).to.eql(template.index_patterns);
-      });
-    });
-
     describe('update', () => {
       it('should add a policy to a template', async () => {
         // Create policy
@@ -78,12 +66,13 @@ export default function({ getService }) {
         await addPolicyToTemplate(templateName, policyName, rolloverAlias).expect(200);
 
         // Fetch the template and verify that the policy has been attached
-        const { body } = await getTemplate(templateName);
+        const { body } = await loadTemplates();
+        const fetchedTemplate = body.find(({ name }) => templateName === name);
         const {
           settings: {
             index: { lifecycle },
           },
-        } = body;
+        } = fetchedTemplate;
         expect(lifecycle.name).to.equal(policyName);
         expect(lifecycle.rollover_alias).to.equal(rolloverAlias);
       });

From 330956ec1a7ea94cc6665147b870075f683d05b3 Mon Sep 17 00:00:00 2001
From: Dmitry Lemeshko <dzmitry.lemechko@elastic.co>
Date: Fri, 10 Apr 2020 02:55:28 +0300
Subject: [PATCH 43/78] Code coverage: fix missing coverage after merging oss &
 x-pack data (#63178)

* update nyc & istanbul-babel deps

* update index.js in kbn-pm

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 package.json                  |    4 +-
 packages/kbn-pm/dist/index.js | 1919 ++++++++++++++++-----------------
 yarn.lock                     |  410 ++++---
 3 files changed, 1190 insertions(+), 1143 deletions(-)

diff --git a/package.json b/package.json
index ea930d07e7b43..ec72d5b660345 100644
--- a/package.json
+++ b/package.json
@@ -396,7 +396,7 @@
     "axe-core": "^3.4.1",
     "babel-eslint": "^10.0.3",
     "babel-jest": "^24.9.0",
-    "babel-plugin-istanbul": "^5.2.0",
+    "babel-plugin-istanbul": "^6.0.0",
     "backport": "5.1.3",
     "chai": "3.5.0",
     "chance": "1.0.18",
@@ -469,7 +469,7 @@
     "nock": "12.0.3",
     "node-sass": "^4.13.1",
     "normalize-path": "^3.0.0",
-    "nyc": "^14.1.1",
+    "nyc": "^15.0.1",
     "pixelmatch": "^5.1.0",
     "pkg-up": "^2.0.0",
     "pngjs": "^3.4.0",
diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js
index 7a858deff41d3..399720f310f67 100644
--- a/packages/kbn-pm/dist/index.js
+++ b/packages/kbn-pm/dist/index.js
@@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; });
 
-/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(704);
+/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(703);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; });
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; });
@@ -105,10 +105,10 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(515);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Project", function() { return _utils_project__WEBPACK_IMPORTED_MODULE_3__["Project"]; });
 
-/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(577);
+/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(576);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "copyWorkspacePackages", function() { return _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__["copyWorkspacePackages"]; });
 
-/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(578);
+/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(577);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; });
 
 /*
@@ -152,7 +152,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17);
-/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(688);
+/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(687);
 /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
@@ -2506,9 +2506,9 @@ module.exports = require("path");
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; });
 /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18);
-/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(585);
-/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(685);
-/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(686);
+/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(584);
+/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(684);
+/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(685);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
  * license agreements. See the NOTICE file distributed with
@@ -2551,8 +2551,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(34);
 /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(499);
 /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(500);
-/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(579);
-/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(584);
+/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(578);
+/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(583);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
  * license agreements. See the NOTICE file distributed with
@@ -43866,7 +43866,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(514);
 /* harmony import */ var _project__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(515);
-/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(577);
+/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(576);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
  * license agreements. See the NOTICE file distributed with
@@ -47386,7 +47386,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(514);
 /* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34);
 /* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(516);
-/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(562);
+/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(561);
 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
 
 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
@@ -52557,8 +52557,8 @@ const fs = __webpack_require__(545);
 const writeFileAtomic = __webpack_require__(549);
 const sortKeys = __webpack_require__(556);
 const makeDir = __webpack_require__(558);
-const pify = __webpack_require__(560);
-const detectIndent = __webpack_require__(561);
+const pify = __webpack_require__(559);
+const detectIndent = __webpack_require__(560);
 
 const init = (fn, filePath, data, options) => {
 	if (!filePath) {
@@ -54852,81 +54852,6 @@ module.exports = (input, options) => {
 "use strict";
 
 
-const processFn = (fn, options) => function (...args) {
-	const P = options.promiseModule;
-
-	return new P((resolve, reject) => {
-		if (options.multiArgs) {
-			args.push((...result) => {
-				if (options.errorFirst) {
-					if (result[0]) {
-						reject(result);
-					} else {
-						result.shift();
-						resolve(result);
-					}
-				} else {
-					resolve(result);
-				}
-			});
-		} else if (options.errorFirst) {
-			args.push((error, result) => {
-				if (error) {
-					reject(error);
-				} else {
-					resolve(result);
-				}
-			});
-		} else {
-			args.push(resolve);
-		}
-
-		fn.apply(this, args);
-	});
-};
-
-module.exports = (input, options) => {
-	options = Object.assign({
-		exclude: [/.+(Sync|Stream)$/],
-		errorFirst: true,
-		promiseModule: Promise
-	}, options);
-
-	const objType = typeof input;
-	if (!(input !== null && (objType === 'object' || objType === 'function'))) {
-		throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``);
-	}
-
-	const filter = key => {
-		const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key);
-		return options.include ? options.include.some(match) : !options.exclude.some(match);
-	};
-
-	let ret;
-	if (objType === 'function') {
-		ret = function (...args) {
-			return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args);
-		};
-	} else {
-		ret = Object.create(Object.getPrototypeOf(input));
-	}
-
-	for (const key in input) { // eslint-disable-line guard-for-in
-		const property = input[key];
-		ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property;
-	}
-
-	return ret;
-};
-
-
-/***/ }),
-/* 561 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
 // detect either spaces or tabs but not both to properly handle tabs
 // for indentation and spaces for alignment
 const INDENT_RE = /^(?:( )+|\t+)/;
@@ -55050,7 +54975,7 @@ module.exports = str => {
 
 
 /***/ }),
-/* 562 */
+/* 561 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -55059,7 +54984,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runScriptInPackage", function() { return runScriptInPackage; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runScriptInPackageStreaming", function() { return runScriptInPackageStreaming; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "yarnWorkspacesInfo", function() { return yarnWorkspacesInfo; });
-/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(563);
+/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(562);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
  * license agreements. See the NOTICE file distributed with
@@ -55129,7 +55054,7 @@ async function yarnWorkspacesInfo(directory) {
 }
 
 /***/ }),
-/* 563 */
+/* 562 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -55140,9 +55065,9 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(351);
 /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(564);
+/* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(563);
 /* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(log_symbols__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(569);
+/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(568);
 /* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__);
 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
 
@@ -55208,12 +55133,12 @@ function spawnStreaming(command, args, opts, {
 }
 
 /***/ }),
-/* 564 */
+/* 563 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const chalk = __webpack_require__(565);
+const chalk = __webpack_require__(564);
 
 const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color';
 
@@ -55235,16 +55160,16 @@ module.exports = isSupported ? main : fallbacks;
 
 
 /***/ }),
-/* 565 */
+/* 564 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const escapeStringRegexp = __webpack_require__(3);
-const ansiStyles = __webpack_require__(566);
-const stdoutColor = __webpack_require__(567).stdout;
+const ansiStyles = __webpack_require__(565);
+const stdoutColor = __webpack_require__(566).stdout;
 
-const template = __webpack_require__(568);
+const template = __webpack_require__(567);
 
 const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
 
@@ -55470,7 +55395,7 @@ module.exports.default = module.exports; // For TypeScript
 
 
 /***/ }),
-/* 566 */
+/* 565 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -55643,7 +55568,7 @@ Object.defineProperty(module, 'exports', {
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module)))
 
 /***/ }),
-/* 567 */
+/* 566 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -55785,7 +55710,7 @@ module.exports = {
 
 
 /***/ }),
-/* 568 */
+/* 567 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -55920,7 +55845,7 @@ module.exports = (chalk, tmp) => {
 
 
 /***/ }),
-/* 569 */
+/* 568 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Copyright IBM Corp. 2014,2018. All Rights Reserved.
@@ -55928,12 +55853,12 @@ module.exports = (chalk, tmp) => {
 // This file is licensed under the Apache License 2.0.
 // License text available at https://opensource.org/licenses/Apache-2.0
 
-module.exports = __webpack_require__(570);
-module.exports.cli = __webpack_require__(574);
+module.exports = __webpack_require__(569);
+module.exports.cli = __webpack_require__(573);
 
 
 /***/ }),
-/* 570 */
+/* 569 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -55948,9 +55873,9 @@ var stream = __webpack_require__(27);
 var util = __webpack_require__(29);
 var fs = __webpack_require__(23);
 
-var through = __webpack_require__(571);
-var duplexer = __webpack_require__(572);
-var StringDecoder = __webpack_require__(573).StringDecoder;
+var through = __webpack_require__(570);
+var duplexer = __webpack_require__(571);
+var StringDecoder = __webpack_require__(572).StringDecoder;
 
 module.exports = Logger;
 
@@ -56139,7 +56064,7 @@ function lineMerger(host) {
 
 
 /***/ }),
-/* 571 */
+/* 570 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var Stream = __webpack_require__(27)
@@ -56253,7 +56178,7 @@ function through (write, end, opts) {
 
 
 /***/ }),
-/* 572 */
+/* 571 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var Stream = __webpack_require__(27)
@@ -56346,13 +56271,13 @@ function duplex(writer, reader) {
 
 
 /***/ }),
-/* 573 */
+/* 572 */
 /***/ (function(module, exports) {
 
 module.exports = require("string_decoder");
 
 /***/ }),
-/* 574 */
+/* 573 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -56363,11 +56288,11 @@ module.exports = require("string_decoder");
 
 
 
-var minimist = __webpack_require__(575);
+var minimist = __webpack_require__(574);
 var path = __webpack_require__(16);
 
-var Logger = __webpack_require__(570);
-var pkg = __webpack_require__(576);
+var Logger = __webpack_require__(569);
+var pkg = __webpack_require__(575);
 
 module.exports = cli;
 
@@ -56421,7 +56346,7 @@ function usage($0, p) {
 
 
 /***/ }),
-/* 575 */
+/* 574 */
 /***/ (function(module, exports) {
 
 module.exports = function (args, opts) {
@@ -56663,13 +56588,13 @@ function isNumber (x) {
 
 
 /***/ }),
-/* 576 */
+/* 575 */
 /***/ (function(module) {
 
 module.exports = JSON.parse("{\"name\":\"strong-log-transformer\",\"version\":\"2.1.0\",\"description\":\"Stream transformer that prefixes lines with timestamps and other things.\",\"author\":\"Ryan Graham <ryan@strongloop.com>\",\"license\":\"Apache-2.0\",\"repository\":{\"type\":\"git\",\"url\":\"git://github.com/strongloop/strong-log-transformer\"},\"keywords\":[\"logging\",\"streams\"],\"bugs\":{\"url\":\"https://github.com/strongloop/strong-log-transformer/issues\"},\"homepage\":\"https://github.com/strongloop/strong-log-transformer\",\"directories\":{\"test\":\"test\"},\"bin\":{\"sl-log-transformer\":\"bin/sl-log-transformer.js\"},\"main\":\"index.js\",\"scripts\":{\"test\":\"tap --100 test/test-*\"},\"dependencies\":{\"duplexer\":\"^0.1.1\",\"minimist\":\"^1.2.0\",\"through\":\"^2.3.4\"},\"devDependencies\":{\"tap\":\"^12.0.1\"},\"engines\":{\"node\":\">=4\"}}");
 
 /***/ }),
-/* 577 */
+/* 576 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -56682,7 +56607,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29);
 /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(578);
+/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(577);
 /* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20);
 /* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(516);
 /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(500);
@@ -56777,7 +56702,7 @@ function packagesFromGlobPattern({
 }
 
 /***/ }),
-/* 578 */
+/* 577 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -56847,7 +56772,7 @@ function getProjectPaths({
 }
 
 /***/ }),
-/* 579 */
+/* 578 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -56855,13 +56780,13 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getAllChecksums", function() { return getAllChecksums; });
 /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(23);
 /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(580);
+/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(579);
 /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29);
 /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(351);
 /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_3__);
-/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(581);
+/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(580);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
  * license agreements. See the NOTICE file distributed with
@@ -57087,19 +57012,19 @@ async function getAllChecksums(kbn, log) {
 }
 
 /***/ }),
-/* 580 */
+/* 579 */
 /***/ (function(module, exports) {
 
 module.exports = require("crypto");
 
 /***/ }),
-/* 581 */
+/* 580 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readYarnLock", function() { return readYarnLock; });
-/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(582);
+/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(581);
 /* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(20);
 /*
@@ -57143,7 +57068,7 @@ async function readYarnLock(kbn) {
 }
 
 /***/ }),
-/* 582 */
+/* 581 */
 /***/ (function(module, exports, __webpack_require__) {
 
 module.exports =
@@ -58702,7 +58627,7 @@ module.exports = invariant;
 /* 9 */
 /***/ (function(module, exports) {
 
-module.exports = __webpack_require__(580);
+module.exports = __webpack_require__(579);
 
 /***/ }),
 /* 10 */,
@@ -61026,7 +60951,7 @@ function onceStrict (fn) {
 /* 63 */
 /***/ (function(module, exports) {
 
-module.exports = __webpack_require__(583);
+module.exports = __webpack_require__(582);
 
 /***/ }),
 /* 64 */,
@@ -67421,13 +67346,13 @@ module.exports = process && support(supportLevel);
 /******/ ]);
 
 /***/ }),
-/* 583 */
+/* 582 */
 /***/ (function(module, exports) {
 
 module.exports = require("buffer");
 
 /***/ }),
-/* 584 */
+/* 583 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -67524,7 +67449,7 @@ class BootstrapCacheFile {
 }
 
 /***/ }),
-/* 585 */
+/* 584 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -67532,9 +67457,9 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CleanCommand", function() { return CleanCommand; });
 /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(586);
+/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(585);
 /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(674);
+/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(673);
 /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
@@ -67633,21 +67558,21 @@ const CleanCommand = {
 };
 
 /***/ }),
-/* 586 */
+/* 585 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const {promisify} = __webpack_require__(29);
 const path = __webpack_require__(16);
-const globby = __webpack_require__(587);
-const isGlob = __webpack_require__(604);
-const slash = __webpack_require__(665);
+const globby = __webpack_require__(586);
+const isGlob = __webpack_require__(603);
+const slash = __webpack_require__(664);
 const gracefulFs = __webpack_require__(22);
-const isPathCwd = __webpack_require__(667);
-const isPathInside = __webpack_require__(668);
-const rimraf = __webpack_require__(669);
-const pMap = __webpack_require__(670);
+const isPathCwd = __webpack_require__(666);
+const isPathInside = __webpack_require__(667);
+const rimraf = __webpack_require__(668);
+const pMap = __webpack_require__(669);
 
 const rimrafP = promisify(rimraf);
 
@@ -67761,19 +67686,19 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options
 
 
 /***/ }),
-/* 587 */
+/* 586 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const fs = __webpack_require__(23);
-const arrayUnion = __webpack_require__(588);
-const merge2 = __webpack_require__(589);
-const glob = __webpack_require__(590);
-const fastGlob = __webpack_require__(595);
-const dirGlob = __webpack_require__(661);
-const gitignore = __webpack_require__(663);
-const {FilterStream, UniqueStream} = __webpack_require__(666);
+const arrayUnion = __webpack_require__(587);
+const merge2 = __webpack_require__(588);
+const glob = __webpack_require__(589);
+const fastGlob = __webpack_require__(594);
+const dirGlob = __webpack_require__(660);
+const gitignore = __webpack_require__(662);
+const {FilterStream, UniqueStream} = __webpack_require__(665);
 
 const DEFAULT_FILTER = () => false;
 
@@ -67946,7 +67871,7 @@ module.exports.gitignore = gitignore;
 
 
 /***/ }),
-/* 588 */
+/* 587 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -67958,7 +67883,7 @@ module.exports = (...arguments_) => {
 
 
 /***/ }),
-/* 589 */
+/* 588 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -68072,7 +67997,7 @@ function pauseStreams (streams, options) {
 
 
 /***/ }),
-/* 590 */
+/* 589 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Approach:
@@ -68121,13 +68046,13 @@ var fs = __webpack_require__(23)
 var rp = __webpack_require__(502)
 var minimatch = __webpack_require__(504)
 var Minimatch = minimatch.Minimatch
-var inherits = __webpack_require__(591)
+var inherits = __webpack_require__(590)
 var EE = __webpack_require__(379).EventEmitter
 var path = __webpack_require__(16)
 var assert = __webpack_require__(30)
 var isAbsolute = __webpack_require__(510)
-var globSync = __webpack_require__(593)
-var common = __webpack_require__(594)
+var globSync = __webpack_require__(592)
+var common = __webpack_require__(593)
 var alphasort = common.alphasort
 var alphasorti = common.alphasorti
 var setopts = common.setopts
@@ -68868,7 +68793,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
 
 
 /***/ }),
-/* 591 */
+/* 590 */
 /***/ (function(module, exports, __webpack_require__) {
 
 try {
@@ -68878,12 +68803,12 @@ try {
   module.exports = util.inherits;
 } catch (e) {
   /* istanbul ignore next */
-  module.exports = __webpack_require__(592);
+  module.exports = __webpack_require__(591);
 }
 
 
 /***/ }),
-/* 592 */
+/* 591 */
 /***/ (function(module, exports) {
 
 if (typeof Object.create === 'function') {
@@ -68916,7 +68841,7 @@ if (typeof Object.create === 'function') {
 
 
 /***/ }),
-/* 593 */
+/* 592 */
 /***/ (function(module, exports, __webpack_require__) {
 
 module.exports = globSync
@@ -68926,12 +68851,12 @@ var fs = __webpack_require__(23)
 var rp = __webpack_require__(502)
 var minimatch = __webpack_require__(504)
 var Minimatch = minimatch.Minimatch
-var Glob = __webpack_require__(590).Glob
+var Glob = __webpack_require__(589).Glob
 var util = __webpack_require__(29)
 var path = __webpack_require__(16)
 var assert = __webpack_require__(30)
 var isAbsolute = __webpack_require__(510)
-var common = __webpack_require__(594)
+var common = __webpack_require__(593)
 var alphasort = common.alphasort
 var alphasorti = common.alphasorti
 var setopts = common.setopts
@@ -69408,7 +69333,7 @@ GlobSync.prototype._makeAbs = function (f) {
 
 
 /***/ }),
-/* 594 */
+/* 593 */
 /***/ (function(module, exports, __webpack_require__) {
 
 exports.alphasort = alphasort
@@ -69654,17 +69579,17 @@ function childrenIgnored (self, path) {
 
 
 /***/ }),
-/* 595 */
+/* 594 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const taskManager = __webpack_require__(596);
-const async_1 = __webpack_require__(624);
-const stream_1 = __webpack_require__(657);
-const sync_1 = __webpack_require__(658);
-const settings_1 = __webpack_require__(660);
-const utils = __webpack_require__(597);
+const taskManager = __webpack_require__(595);
+const async_1 = __webpack_require__(623);
+const stream_1 = __webpack_require__(656);
+const sync_1 = __webpack_require__(657);
+const settings_1 = __webpack_require__(659);
+const utils = __webpack_require__(596);
 function FastGlob(source, options) {
     try {
         assertPatternsInput(source);
@@ -69722,13 +69647,13 @@ module.exports = FastGlob;
 
 
 /***/ }),
-/* 596 */
+/* 595 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils = __webpack_require__(597);
+const utils = __webpack_require__(596);
 function generate(patterns, settings) {
     const positivePatterns = getPositivePatterns(patterns);
     const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore);
@@ -69796,28 +69721,28 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask;
 
 
 /***/ }),
-/* 597 */
+/* 596 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const array = __webpack_require__(598);
+const array = __webpack_require__(597);
 exports.array = array;
-const errno = __webpack_require__(599);
+const errno = __webpack_require__(598);
 exports.errno = errno;
-const fs = __webpack_require__(600);
+const fs = __webpack_require__(599);
 exports.fs = fs;
-const path = __webpack_require__(601);
+const path = __webpack_require__(600);
 exports.path = path;
-const pattern = __webpack_require__(602);
+const pattern = __webpack_require__(601);
 exports.pattern = pattern;
-const stream = __webpack_require__(623);
+const stream = __webpack_require__(622);
 exports.stream = stream;
 
 
 /***/ }),
-/* 598 */
+/* 597 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -69830,7 +69755,7 @@ exports.flatten = flatten;
 
 
 /***/ }),
-/* 599 */
+/* 598 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -69843,7 +69768,7 @@ exports.isEnoentCodeError = isEnoentCodeError;
 
 
 /***/ }),
-/* 600 */
+/* 599 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -69868,7 +69793,7 @@ exports.createDirentFromStats = createDirentFromStats;
 
 
 /***/ }),
-/* 601 */
+/* 600 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -69889,16 +69814,16 @@ exports.makeAbsolute = makeAbsolute;
 
 
 /***/ }),
-/* 602 */
+/* 601 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const path = __webpack_require__(16);
-const globParent = __webpack_require__(603);
-const isGlob = __webpack_require__(604);
-const micromatch = __webpack_require__(606);
+const globParent = __webpack_require__(602);
+const isGlob = __webpack_require__(603);
+const micromatch = __webpack_require__(605);
 const GLOBSTAR = '**';
 function isStaticPattern(pattern) {
     return !isDynamicPattern(pattern);
@@ -69987,13 +69912,13 @@ exports.matchAny = matchAny;
 
 
 /***/ }),
-/* 603 */
+/* 602 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isGlob = __webpack_require__(604);
+var isGlob = __webpack_require__(603);
 var pathPosixDirname = __webpack_require__(16).posix.dirname;
 var isWin32 = __webpack_require__(11).platform() === 'win32';
 
@@ -70028,7 +69953,7 @@ module.exports = function globParent(str) {
 
 
 /***/ }),
-/* 604 */
+/* 603 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /*!
@@ -70038,7 +69963,7 @@ module.exports = function globParent(str) {
  * Released under the MIT License.
  */
 
-var isExtglob = __webpack_require__(605);
+var isExtglob = __webpack_require__(604);
 var chars = { '{': '}', '(': ')', '[': ']'};
 var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
 var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/;
@@ -70082,7 +70007,7 @@ module.exports = function isGlob(str, options) {
 
 
 /***/ }),
-/* 605 */
+/* 604 */
 /***/ (function(module, exports) {
 
 /*!
@@ -70108,16 +70033,16 @@ module.exports = function isExtglob(str) {
 
 
 /***/ }),
-/* 606 */
+/* 605 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const util = __webpack_require__(29);
-const braces = __webpack_require__(607);
-const picomatch = __webpack_require__(617);
-const utils = __webpack_require__(620);
+const braces = __webpack_require__(606);
+const picomatch = __webpack_require__(616);
+const utils = __webpack_require__(619);
 const isEmptyString = val => typeof val === 'string' && (val === '' || val === './');
 
 /**
@@ -70582,16 +70507,16 @@ module.exports = micromatch;
 
 
 /***/ }),
-/* 607 */
+/* 606 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const stringify = __webpack_require__(608);
-const compile = __webpack_require__(610);
-const expand = __webpack_require__(614);
-const parse = __webpack_require__(615);
+const stringify = __webpack_require__(607);
+const compile = __webpack_require__(609);
+const expand = __webpack_require__(613);
+const parse = __webpack_require__(614);
 
 /**
  * Expand the given pattern or create a regex-compatible string.
@@ -70759,13 +70684,13 @@ module.exports = braces;
 
 
 /***/ }),
-/* 608 */
+/* 607 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const utils = __webpack_require__(609);
+const utils = __webpack_require__(608);
 
 module.exports = (ast, options = {}) => {
   let stringify = (node, parent = {}) => {
@@ -70798,7 +70723,7 @@ module.exports = (ast, options = {}) => {
 
 
 /***/ }),
-/* 609 */
+/* 608 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -70917,14 +70842,14 @@ exports.flatten = (...args) => {
 
 
 /***/ }),
-/* 610 */
+/* 609 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const fill = __webpack_require__(611);
-const utils = __webpack_require__(609);
+const fill = __webpack_require__(610);
+const utils = __webpack_require__(608);
 
 const compile = (ast, options = {}) => {
   let walk = (node, parent = {}) => {
@@ -70981,7 +70906,7 @@ module.exports = compile;
 
 
 /***/ }),
-/* 611 */
+/* 610 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -70995,7 +70920,7 @@ module.exports = compile;
 
 
 const util = __webpack_require__(29);
-const toRegexRange = __webpack_require__(612);
+const toRegexRange = __webpack_require__(611);
 
 const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
 
@@ -71237,7 +71162,7 @@ module.exports = fill;
 
 
 /***/ }),
-/* 612 */
+/* 611 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -71250,7 +71175,7 @@ module.exports = fill;
 
 
 
-const isNumber = __webpack_require__(613);
+const isNumber = __webpack_require__(612);
 
 const toRegexRange = (min, max, options) => {
   if (isNumber(min) === false) {
@@ -71532,7 +71457,7 @@ module.exports = toRegexRange;
 
 
 /***/ }),
-/* 613 */
+/* 612 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -71557,15 +71482,15 @@ module.exports = function(num) {
 
 
 /***/ }),
-/* 614 */
+/* 613 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const fill = __webpack_require__(611);
-const stringify = __webpack_require__(608);
-const utils = __webpack_require__(609);
+const fill = __webpack_require__(610);
+const stringify = __webpack_require__(607);
+const utils = __webpack_require__(608);
 
 const append = (queue = '', stash = '', enclose = false) => {
   let result = [];
@@ -71677,13 +71602,13 @@ module.exports = expand;
 
 
 /***/ }),
-/* 615 */
+/* 614 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const stringify = __webpack_require__(608);
+const stringify = __webpack_require__(607);
 
 /**
  * Constants
@@ -71705,7 +71630,7 @@ const {
   CHAR_SINGLE_QUOTE, /* ' */
   CHAR_NO_BREAK_SPACE,
   CHAR_ZERO_WIDTH_NOBREAK_SPACE
-} = __webpack_require__(616);
+} = __webpack_require__(615);
 
 /**
  * parse
@@ -72017,7 +71942,7 @@ module.exports = parse;
 
 
 /***/ }),
-/* 616 */
+/* 615 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -72081,26 +72006,26 @@ module.exports = {
 
 
 /***/ }),
-/* 617 */
+/* 616 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-module.exports = __webpack_require__(618);
+module.exports = __webpack_require__(617);
 
 
 /***/ }),
-/* 618 */
+/* 617 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const path = __webpack_require__(16);
-const scan = __webpack_require__(619);
-const parse = __webpack_require__(622);
-const utils = __webpack_require__(620);
+const scan = __webpack_require__(618);
+const parse = __webpack_require__(621);
+const utils = __webpack_require__(619);
 
 /**
  * Creates a matcher function from one or more glob patterns. The
@@ -72403,7 +72328,7 @@ picomatch.toRegex = (source, options) => {
  * @return {Object}
  */
 
-picomatch.constants = __webpack_require__(621);
+picomatch.constants = __webpack_require__(620);
 
 /**
  * Expose "picomatch"
@@ -72413,13 +72338,13 @@ module.exports = picomatch;
 
 
 /***/ }),
-/* 619 */
+/* 618 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const utils = __webpack_require__(620);
+const utils = __webpack_require__(619);
 
 const {
   CHAR_ASTERISK,             /* * */
@@ -72437,7 +72362,7 @@ const {
   CHAR_RIGHT_CURLY_BRACE,    /* } */
   CHAR_RIGHT_PARENTHESES,    /* ) */
   CHAR_RIGHT_SQUARE_BRACKET /* ] */
-} = __webpack_require__(621);
+} = __webpack_require__(620);
 
 const isPathSeparator = code => {
   return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
@@ -72639,7 +72564,7 @@ module.exports = (input, options) => {
 
 
 /***/ }),
-/* 620 */
+/* 619 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -72651,7 +72576,7 @@ const {
   REGEX_SPECIAL_CHARS,
   REGEX_SPECIAL_CHARS_GLOBAL,
   REGEX_REMOVE_BACKSLASH
-} = __webpack_require__(621);
+} = __webpack_require__(620);
 
 exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
 exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str);
@@ -72689,7 +72614,7 @@ exports.escapeLast = (input, char, lastIdx) => {
 
 
 /***/ }),
-/* 621 */
+/* 620 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -72875,14 +72800,14 @@ module.exports = {
 
 
 /***/ }),
-/* 622 */
+/* 621 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const utils = __webpack_require__(620);
-const constants = __webpack_require__(621);
+const utils = __webpack_require__(619);
+const constants = __webpack_require__(620);
 
 /**
  * Constants
@@ -73893,13 +73818,13 @@ module.exports = parse;
 
 
 /***/ }),
-/* 623 */
+/* 622 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const merge2 = __webpack_require__(589);
+const merge2 = __webpack_require__(588);
 function merge(streams) {
     const mergedStream = merge2(streams);
     streams.forEach((stream) => {
@@ -73911,14 +73836,14 @@ exports.merge = merge;
 
 
 /***/ }),
-/* 624 */
+/* 623 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const stream_1 = __webpack_require__(625);
-const provider_1 = __webpack_require__(652);
+const stream_1 = __webpack_require__(624);
+const provider_1 = __webpack_require__(651);
 class ProviderAsync extends provider_1.default {
     constructor() {
         super(...arguments);
@@ -73946,16 +73871,16 @@ exports.default = ProviderAsync;
 
 
 /***/ }),
-/* 625 */
+/* 624 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const stream_1 = __webpack_require__(27);
-const fsStat = __webpack_require__(626);
-const fsWalk = __webpack_require__(631);
-const reader_1 = __webpack_require__(651);
+const fsStat = __webpack_require__(625);
+const fsWalk = __webpack_require__(630);
+const reader_1 = __webpack_require__(650);
 class ReaderStream extends reader_1.default {
     constructor() {
         super(...arguments);
@@ -74008,15 +73933,15 @@ exports.default = ReaderStream;
 
 
 /***/ }),
-/* 626 */
+/* 625 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const async = __webpack_require__(627);
-const sync = __webpack_require__(628);
-const settings_1 = __webpack_require__(629);
+const async = __webpack_require__(626);
+const sync = __webpack_require__(627);
+const settings_1 = __webpack_require__(628);
 exports.Settings = settings_1.default;
 function stat(path, optionsOrSettingsOrCallback, callback) {
     if (typeof optionsOrSettingsOrCallback === 'function') {
@@ -74039,7 +73964,7 @@ function getSettings(settingsOrOptions = {}) {
 
 
 /***/ }),
-/* 627 */
+/* 626 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74077,7 +74002,7 @@ function callSuccessCallback(callback, result) {
 
 
 /***/ }),
-/* 628 */
+/* 627 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74106,13 +74031,13 @@ exports.read = read;
 
 
 /***/ }),
-/* 629 */
+/* 628 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fs = __webpack_require__(630);
+const fs = __webpack_require__(629);
 class Settings {
     constructor(_options = {}) {
         this._options = _options;
@@ -74129,7 +74054,7 @@ exports.default = Settings;
 
 
 /***/ }),
-/* 630 */
+/* 629 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74152,16 +74077,16 @@ exports.createFileSystemAdapter = createFileSystemAdapter;
 
 
 /***/ }),
-/* 631 */
+/* 630 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const async_1 = __webpack_require__(632);
-const stream_1 = __webpack_require__(647);
-const sync_1 = __webpack_require__(648);
-const settings_1 = __webpack_require__(650);
+const async_1 = __webpack_require__(631);
+const stream_1 = __webpack_require__(646);
+const sync_1 = __webpack_require__(647);
+const settings_1 = __webpack_require__(649);
 exports.Settings = settings_1.default;
 function walk(dir, optionsOrSettingsOrCallback, callback) {
     if (typeof optionsOrSettingsOrCallback === 'function') {
@@ -74191,13 +74116,13 @@ function getSettings(settingsOrOptions = {}) {
 
 
 /***/ }),
-/* 632 */
+/* 631 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const async_1 = __webpack_require__(633);
+const async_1 = __webpack_require__(632);
 class AsyncProvider {
     constructor(_root, _settings) {
         this._root = _root;
@@ -74228,17 +74153,17 @@ function callSuccessCallback(callback, entries) {
 
 
 /***/ }),
-/* 633 */
+/* 632 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const events_1 = __webpack_require__(379);
-const fsScandir = __webpack_require__(634);
-const fastq = __webpack_require__(643);
-const common = __webpack_require__(645);
-const reader_1 = __webpack_require__(646);
+const fsScandir = __webpack_require__(633);
+const fastq = __webpack_require__(642);
+const common = __webpack_require__(644);
+const reader_1 = __webpack_require__(645);
 class AsyncReader extends reader_1.default {
     constructor(_root, _settings) {
         super(_root, _settings);
@@ -74328,15 +74253,15 @@ exports.default = AsyncReader;
 
 
 /***/ }),
-/* 634 */
+/* 633 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const async = __webpack_require__(635);
-const sync = __webpack_require__(640);
-const settings_1 = __webpack_require__(641);
+const async = __webpack_require__(634);
+const sync = __webpack_require__(639);
+const settings_1 = __webpack_require__(640);
 exports.Settings = settings_1.default;
 function scandir(path, optionsOrSettingsOrCallback, callback) {
     if (typeof optionsOrSettingsOrCallback === 'function') {
@@ -74359,16 +74284,16 @@ function getSettings(settingsOrOptions = {}) {
 
 
 /***/ }),
-/* 635 */
+/* 634 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fsStat = __webpack_require__(626);
-const rpl = __webpack_require__(636);
-const constants_1 = __webpack_require__(637);
-const utils = __webpack_require__(638);
+const fsStat = __webpack_require__(625);
+const rpl = __webpack_require__(635);
+const constants_1 = __webpack_require__(636);
+const utils = __webpack_require__(637);
 function read(dir, settings, callback) {
     if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) {
         return readdirWithFileTypes(dir, settings, callback);
@@ -74457,7 +74382,7 @@ function callSuccessCallback(callback, result) {
 
 
 /***/ }),
-/* 636 */
+/* 635 */
 /***/ (function(module, exports) {
 
 module.exports = runParallel
@@ -74511,7 +74436,7 @@ function runParallel (tasks, cb) {
 
 
 /***/ }),
-/* 637 */
+/* 636 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74527,18 +74452,18 @@ exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = MAJOR_VERSION > 10 || (MAJOR_VERSIO
 
 
 /***/ }),
-/* 638 */
+/* 637 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fs = __webpack_require__(639);
+const fs = __webpack_require__(638);
 exports.fs = fs;
 
 
 /***/ }),
-/* 639 */
+/* 638 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74563,15 +74488,15 @@ exports.createDirentFromStats = createDirentFromStats;
 
 
 /***/ }),
-/* 640 */
+/* 639 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fsStat = __webpack_require__(626);
-const constants_1 = __webpack_require__(637);
-const utils = __webpack_require__(638);
+const fsStat = __webpack_require__(625);
+const constants_1 = __webpack_require__(636);
+const utils = __webpack_require__(637);
 function read(dir, settings) {
     if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) {
         return readdirWithFileTypes(dir, settings);
@@ -74622,15 +74547,15 @@ exports.readdir = readdir;
 
 
 /***/ }),
-/* 641 */
+/* 640 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const path = __webpack_require__(16);
-const fsStat = __webpack_require__(626);
-const fs = __webpack_require__(642);
+const fsStat = __webpack_require__(625);
+const fs = __webpack_require__(641);
 class Settings {
     constructor(_options = {}) {
         this._options = _options;
@@ -74653,7 +74578,7 @@ exports.default = Settings;
 
 
 /***/ }),
-/* 642 */
+/* 641 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74678,13 +74603,13 @@ exports.createFileSystemAdapter = createFileSystemAdapter;
 
 
 /***/ }),
-/* 643 */
+/* 642 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var reusify = __webpack_require__(644)
+var reusify = __webpack_require__(643)
 
 function fastqueue (context, worker, concurrency) {
   if (typeof context === 'function') {
@@ -74858,7 +74783,7 @@ module.exports = fastqueue
 
 
 /***/ }),
-/* 644 */
+/* 643 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74898,7 +74823,7 @@ module.exports = reusify
 
 
 /***/ }),
-/* 645 */
+/* 644 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -74929,13 +74854,13 @@ exports.joinPathSegments = joinPathSegments;
 
 
 /***/ }),
-/* 646 */
+/* 645 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const common = __webpack_require__(645);
+const common = __webpack_require__(644);
 class Reader {
     constructor(_root, _settings) {
         this._root = _root;
@@ -74947,14 +74872,14 @@ exports.default = Reader;
 
 
 /***/ }),
-/* 647 */
+/* 646 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const stream_1 = __webpack_require__(27);
-const async_1 = __webpack_require__(633);
+const async_1 = __webpack_require__(632);
 class StreamProvider {
     constructor(_root, _settings) {
         this._root = _root;
@@ -74984,13 +74909,13 @@ exports.default = StreamProvider;
 
 
 /***/ }),
-/* 648 */
+/* 647 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const sync_1 = __webpack_require__(649);
+const sync_1 = __webpack_require__(648);
 class SyncProvider {
     constructor(_root, _settings) {
         this._root = _root;
@@ -75005,15 +74930,15 @@ exports.default = SyncProvider;
 
 
 /***/ }),
-/* 649 */
+/* 648 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fsScandir = __webpack_require__(634);
-const common = __webpack_require__(645);
-const reader_1 = __webpack_require__(646);
+const fsScandir = __webpack_require__(633);
+const common = __webpack_require__(644);
+const reader_1 = __webpack_require__(645);
 class SyncReader extends reader_1.default {
     constructor() {
         super(...arguments);
@@ -75071,14 +74996,14 @@ exports.default = SyncReader;
 
 
 /***/ }),
-/* 650 */
+/* 649 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const path = __webpack_require__(16);
-const fsScandir = __webpack_require__(634);
+const fsScandir = __webpack_require__(633);
 class Settings {
     constructor(_options = {}) {
         this._options = _options;
@@ -75104,15 +75029,15 @@ exports.default = Settings;
 
 
 /***/ }),
-/* 651 */
+/* 650 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const path = __webpack_require__(16);
-const fsStat = __webpack_require__(626);
-const utils = __webpack_require__(597);
+const fsStat = __webpack_require__(625);
+const utils = __webpack_require__(596);
 class Reader {
     constructor(_settings) {
         this._settings = _settings;
@@ -75144,17 +75069,17 @@ exports.default = Reader;
 
 
 /***/ }),
-/* 652 */
+/* 651 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const path = __webpack_require__(16);
-const deep_1 = __webpack_require__(653);
-const entry_1 = __webpack_require__(654);
-const error_1 = __webpack_require__(655);
-const entry_2 = __webpack_require__(656);
+const deep_1 = __webpack_require__(652);
+const entry_1 = __webpack_require__(653);
+const error_1 = __webpack_require__(654);
+const entry_2 = __webpack_require__(655);
 class Provider {
     constructor(_settings) {
         this._settings = _settings;
@@ -75199,13 +75124,13 @@ exports.default = Provider;
 
 
 /***/ }),
-/* 653 */
+/* 652 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils = __webpack_require__(597);
+const utils = __webpack_require__(596);
 class DeepFilter {
     constructor(_settings, _micromatchOptions) {
         this._settings = _settings;
@@ -75265,13 +75190,13 @@ exports.default = DeepFilter;
 
 
 /***/ }),
-/* 654 */
+/* 653 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils = __webpack_require__(597);
+const utils = __webpack_require__(596);
 class EntryFilter {
     constructor(_settings, _micromatchOptions) {
         this._settings = _settings;
@@ -75326,13 +75251,13 @@ exports.default = EntryFilter;
 
 
 /***/ }),
-/* 655 */
+/* 654 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils = __webpack_require__(597);
+const utils = __webpack_require__(596);
 class ErrorFilter {
     constructor(_settings) {
         this._settings = _settings;
@@ -75348,13 +75273,13 @@ exports.default = ErrorFilter;
 
 
 /***/ }),
-/* 656 */
+/* 655 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils = __webpack_require__(597);
+const utils = __webpack_require__(596);
 class EntryTransformer {
     constructor(_settings) {
         this._settings = _settings;
@@ -75381,15 +75306,15 @@ exports.default = EntryTransformer;
 
 
 /***/ }),
-/* 657 */
+/* 656 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 const stream_1 = __webpack_require__(27);
-const stream_2 = __webpack_require__(625);
-const provider_1 = __webpack_require__(652);
+const stream_2 = __webpack_require__(624);
+const provider_1 = __webpack_require__(651);
 class ProviderStream extends provider_1.default {
     constructor() {
         super(...arguments);
@@ -75417,14 +75342,14 @@ exports.default = ProviderStream;
 
 
 /***/ }),
-/* 658 */
+/* 657 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const sync_1 = __webpack_require__(659);
-const provider_1 = __webpack_require__(652);
+const sync_1 = __webpack_require__(658);
+const provider_1 = __webpack_require__(651);
 class ProviderSync extends provider_1.default {
     constructor() {
         super(...arguments);
@@ -75447,15 +75372,15 @@ exports.default = ProviderSync;
 
 
 /***/ }),
-/* 659 */
+/* 658 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fsStat = __webpack_require__(626);
-const fsWalk = __webpack_require__(631);
-const reader_1 = __webpack_require__(651);
+const fsStat = __webpack_require__(625);
+const fsWalk = __webpack_require__(630);
+const reader_1 = __webpack_require__(650);
 class ReaderSync extends reader_1.default {
     constructor() {
         super(...arguments);
@@ -75497,7 +75422,7 @@ exports.default = ReaderSync;
 
 
 /***/ }),
-/* 660 */
+/* 659 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -75557,13 +75482,13 @@ exports.default = Settings;
 
 
 /***/ }),
-/* 661 */
+/* 660 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const path = __webpack_require__(16);
-const pathType = __webpack_require__(662);
+const pathType = __webpack_require__(661);
 
 const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
 
@@ -75639,7 +75564,7 @@ module.exports.sync = (input, options) => {
 
 
 /***/ }),
-/* 662 */
+/* 661 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -75689,7 +75614,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink');
 
 
 /***/ }),
-/* 663 */
+/* 662 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -75697,9 +75622,9 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink');
 const {promisify} = __webpack_require__(29);
 const fs = __webpack_require__(23);
 const path = __webpack_require__(16);
-const fastGlob = __webpack_require__(595);
-const gitIgnore = __webpack_require__(664);
-const slash = __webpack_require__(665);
+const fastGlob = __webpack_require__(594);
+const gitIgnore = __webpack_require__(663);
+const slash = __webpack_require__(664);
 
 const DEFAULT_IGNORE = [
 	'**/node_modules/**',
@@ -75813,7 +75738,7 @@ module.exports.sync = options => {
 
 
 /***/ }),
-/* 664 */
+/* 663 */
 /***/ (function(module, exports) {
 
 // A simple implementation of make-array
@@ -76404,7 +76329,7 @@ if (
 
 
 /***/ }),
-/* 665 */
+/* 664 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -76422,7 +76347,7 @@ module.exports = path => {
 
 
 /***/ }),
-/* 666 */
+/* 665 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -76475,7 +76400,7 @@ module.exports = {
 
 
 /***/ }),
-/* 667 */
+/* 666 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -76497,7 +76422,7 @@ module.exports = path_ => {
 
 
 /***/ }),
-/* 668 */
+/* 667 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -76525,7 +76450,7 @@ module.exports = (childPath, parentPath) => {
 
 
 /***/ }),
-/* 669 */
+/* 668 */
 /***/ (function(module, exports, __webpack_require__) {
 
 const assert = __webpack_require__(30)
@@ -76533,7 +76458,7 @@ const path = __webpack_require__(16)
 const fs = __webpack_require__(23)
 let glob = undefined
 try {
-  glob = __webpack_require__(590)
+  glob = __webpack_require__(589)
 } catch (_err) {
   // treat glob as optional.
 }
@@ -76899,12 +76824,12 @@ rimraf.sync = rimrafSync
 
 
 /***/ }),
-/* 670 */
+/* 669 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const AggregateError = __webpack_require__(671);
+const AggregateError = __webpack_require__(670);
 
 module.exports = async (
 	iterable,
@@ -76987,13 +76912,13 @@ module.exports = async (
 
 
 /***/ }),
-/* 671 */
+/* 670 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const indentString = __webpack_require__(672);
-const cleanStack = __webpack_require__(673);
+const indentString = __webpack_require__(671);
+const cleanStack = __webpack_require__(672);
 
 const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, '');
 
@@ -77041,7 +76966,7 @@ module.exports = AggregateError;
 
 
 /***/ }),
-/* 672 */
+/* 671 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -77083,7 +77008,7 @@ module.exports = (string, count = 1, options) => {
 
 
 /***/ }),
-/* 673 */
+/* 672 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -77130,15 +77055,15 @@ module.exports = (stack, options) => {
 
 
 /***/ }),
-/* 674 */
+/* 673 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const chalk = __webpack_require__(675);
-const cliCursor = __webpack_require__(679);
-const cliSpinners = __webpack_require__(683);
-const logSymbols = __webpack_require__(564);
+const chalk = __webpack_require__(674);
+const cliCursor = __webpack_require__(678);
+const cliSpinners = __webpack_require__(682);
+const logSymbols = __webpack_require__(563);
 
 class Ora {
 	constructor(options) {
@@ -77285,16 +77210,16 @@ module.exports.promise = (action, options) => {
 
 
 /***/ }),
-/* 675 */
+/* 674 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const escapeStringRegexp = __webpack_require__(3);
-const ansiStyles = __webpack_require__(676);
-const stdoutColor = __webpack_require__(677).stdout;
+const ansiStyles = __webpack_require__(675);
+const stdoutColor = __webpack_require__(676).stdout;
 
-const template = __webpack_require__(678);
+const template = __webpack_require__(677);
 
 const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
 
@@ -77520,7 +77445,7 @@ module.exports.default = module.exports; // For TypeScript
 
 
 /***/ }),
-/* 676 */
+/* 675 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -77693,7 +77618,7 @@ Object.defineProperty(module, 'exports', {
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module)))
 
 /***/ }),
-/* 677 */
+/* 676 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -77835,7 +77760,7 @@ module.exports = {
 
 
 /***/ }),
-/* 678 */
+/* 677 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -77970,12 +77895,12 @@ module.exports = (chalk, tmp) => {
 
 
 /***/ }),
-/* 679 */
+/* 678 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const restoreCursor = __webpack_require__(680);
+const restoreCursor = __webpack_require__(679);
 
 let hidden = false;
 
@@ -78016,12 +77941,12 @@ exports.toggle = (force, stream) => {
 
 
 /***/ }),
-/* 680 */
+/* 679 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const onetime = __webpack_require__(681);
+const onetime = __webpack_require__(680);
 const signalExit = __webpack_require__(377);
 
 module.exports = onetime(() => {
@@ -78032,12 +77957,12 @@ module.exports = onetime(() => {
 
 
 /***/ }),
-/* 681 */
+/* 680 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const mimicFn = __webpack_require__(682);
+const mimicFn = __webpack_require__(681);
 
 module.exports = (fn, opts) => {
 	// TODO: Remove this in v3
@@ -78078,7 +78003,7 @@ module.exports = (fn, opts) => {
 
 
 /***/ }),
-/* 682 */
+/* 681 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -78094,22 +78019,22 @@ module.exports = (to, from) => {
 
 
 /***/ }),
-/* 683 */
+/* 682 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-module.exports = __webpack_require__(684);
+module.exports = __webpack_require__(683);
 
 
 /***/ }),
-/* 684 */
+/* 683 */
 /***/ (function(module) {
 
 module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\".  \",\".. \",\"...\",\"   \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\".  \",\".. \",\"...\",\" ..\",\"  .\",\"   \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[    ]\",\"[=   ]\",\"[==  ]\",\"[=== ]\",\"[ ===]\",\"[  ==]\",\"[   =]\",\"[    ]\",\"[   =]\",\"[  ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[==  ]\",\"[=   ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ●    )\",\"(  ●   )\",\"(   ●  )\",\"(    ● )\",\"(     ●)\",\"(    ● )\",\"(   ●  )\",\"(  ●   )\",\"( ●    )\",\"(●     )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂       ▌\",\"▐⠈       ▌\",\"▐ ⠂      ▌\",\"▐ ⠠      ▌\",\"▐  ⡀     ▌\",\"▐  ⠠     ▌\",\"▐   ⠂    ▌\",\"▐   ⠈    ▌\",\"▐    ⠂   ▌\",\"▐    ⠠   ▌\",\"▐     ⡀  ▌\",\"▐     ⠠  ▌\",\"▐      ⠂ ▌\",\"▐      ⠈ ▌\",\"▐       ⠂▌\",\"▐       ⠠▌\",\"▐       ⡀▌\",\"▐      ⠠ ▌\",\"▐      ⠂ ▌\",\"▐     ⠈  ▌\",\"▐     ⠂  ▌\",\"▐    ⠠   ▌\",\"▐    ⡀   ▌\",\"▐   ⠠    ▌\",\"▐   ⠂    ▌\",\"▐  ⠈     ▌\",\"▐  ⠂     ▌\",\"▐ ⠠      ▌\",\"▐ ⡀      ▌\",\"▐⠠       ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]}}");
 
 /***/ }),
-/* 685 */
+/* 684 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -78169,7 +78094,7 @@ const RunCommand = {
 };
 
 /***/ }),
-/* 686 */
+/* 685 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -78180,7 +78105,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34);
 /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(499);
 /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(500);
-/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(687);
+/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(686);
 /*
  * Licensed to Elasticsearch B.V. under one or more contributor
  * license agreements. See the NOTICE file distributed with
@@ -78264,7 +78189,7 @@ const WatchCommand = {
 };
 
 /***/ }),
-/* 687 */
+/* 686 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -78338,7 +78263,7 @@ function waitUntilWatchIsReady(stream, opts = {}) {
 }
 
 /***/ }),
-/* 688 */
+/* 687 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -78346,15 +78271,15 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; });
 /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(689);
+/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(688);
 /* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(indent_string__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(690);
+/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(689);
 /* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(wrap_ansi__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(514);
 /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(34);
 /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(500);
-/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(697);
-/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(698);
+/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(696);
+/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(697);
 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
 
 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
@@ -78442,7 +78367,7 @@ function toArray(value) {
 }
 
 /***/ }),
-/* 689 */
+/* 688 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -78476,13 +78401,13 @@ module.exports = (str, count, opts) => {
 
 
 /***/ }),
-/* 690 */
+/* 689 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const stringWidth = __webpack_require__(691);
-const stripAnsi = __webpack_require__(695);
+const stringWidth = __webpack_require__(690);
+const stripAnsi = __webpack_require__(694);
 
 const ESCAPES = new Set([
 	'\u001B',
@@ -78676,13 +78601,13 @@ module.exports = (str, cols, opts) => {
 
 
 /***/ }),
-/* 691 */
+/* 690 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const stripAnsi = __webpack_require__(692);
-const isFullwidthCodePoint = __webpack_require__(694);
+const stripAnsi = __webpack_require__(691);
+const isFullwidthCodePoint = __webpack_require__(693);
 
 module.exports = str => {
 	if (typeof str !== 'string' || str.length === 0) {
@@ -78719,18 +78644,18 @@ module.exports = str => {
 
 
 /***/ }),
-/* 692 */
+/* 691 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const ansiRegex = __webpack_require__(693);
+const ansiRegex = __webpack_require__(692);
 
 module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input;
 
 
 /***/ }),
-/* 693 */
+/* 692 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -78747,7 +78672,7 @@ module.exports = () => {
 
 
 /***/ }),
-/* 694 */
+/* 693 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -78800,18 +78725,18 @@ module.exports = x => {
 
 
 /***/ }),
-/* 695 */
+/* 694 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const ansiRegex = __webpack_require__(696);
+const ansiRegex = __webpack_require__(695);
 
 module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input;
 
 
 /***/ }),
-/* 696 */
+/* 695 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -78828,7 +78753,7 @@ module.exports = () => {
 
 
 /***/ }),
-/* 697 */
+/* 696 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -78981,7 +78906,7 @@ function addProjectToTree(tree, pathParts, project) {
 }
 
 /***/ }),
-/* 698 */
+/* 697 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -78989,12 +78914,12 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; });
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(699);
+/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(698);
 /* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(703);
+/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(702);
 /* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(500);
-/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(578);
+/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(577);
 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
 
 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
@@ -79135,15 +79060,15 @@ class Kibana {
 }
 
 /***/ }),
-/* 699 */
+/* 698 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const minimatch = __webpack_require__(504);
-const arrayUnion = __webpack_require__(700);
-const arrayDiffer = __webpack_require__(701);
-const arrify = __webpack_require__(702);
+const arrayUnion = __webpack_require__(699);
+const arrayDiffer = __webpack_require__(700);
+const arrify = __webpack_require__(701);
 
 module.exports = (list, patterns, options = {}) => {
 	list = arrify(list);
@@ -79167,7 +79092,7 @@ module.exports = (list, patterns, options = {}) => {
 
 
 /***/ }),
-/* 700 */
+/* 699 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79179,7 +79104,7 @@ module.exports = (...arguments_) => {
 
 
 /***/ }),
-/* 701 */
+/* 700 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79194,7 +79119,7 @@ module.exports = arrayDiffer;
 
 
 /***/ }),
-/* 702 */
+/* 701 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79224,7 +79149,7 @@ module.exports = arrify;
 
 
 /***/ }),
-/* 703 */
+/* 702 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79252,15 +79177,15 @@ module.exports = (childPath, parentPath) => {
 
 
 /***/ }),
-/* 704 */
+/* 703 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
-/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705);
+/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(704);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; });
 
-/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(923);
+/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(922);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; });
 
 /*
@@ -79285,19 +79210,19 @@ __webpack_require__.r(__webpack_exports__);
 
 
 /***/ }),
-/* 705 */
+/* 704 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; });
-/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706);
+/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705);
 /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(586);
+/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(585);
 /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16);
 /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(578);
+/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(577);
 /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20);
 /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34);
 /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(516);
@@ -79433,7 +79358,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) {
 }
 
 /***/ }),
-/* 706 */
+/* 705 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79441,13 +79366,13 @@ async function copyToBuild(project, kibanaRoot, buildRoot) {
 const EventEmitter = __webpack_require__(379);
 const path = __webpack_require__(16);
 const os = __webpack_require__(11);
-const pAll = __webpack_require__(707);
-const arrify = __webpack_require__(709);
-const globby = __webpack_require__(710);
-const isGlob = __webpack_require__(604);
-const cpFile = __webpack_require__(908);
-const junk = __webpack_require__(920);
-const CpyError = __webpack_require__(921);
+const pAll = __webpack_require__(706);
+const arrify = __webpack_require__(708);
+const globby = __webpack_require__(709);
+const isGlob = __webpack_require__(603);
+const cpFile = __webpack_require__(907);
+const junk = __webpack_require__(919);
+const CpyError = __webpack_require__(920);
 
 const defaultOptions = {
 	ignoreJunk: true
@@ -79566,12 +79491,12 @@ module.exports = (source, destination, {
 
 
 /***/ }),
-/* 707 */
+/* 706 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const pMap = __webpack_require__(708);
+const pMap = __webpack_require__(707);
 
 module.exports = (iterable, options) => pMap(iterable, element => element(), options);
 // TODO: Remove this for the next major release
@@ -79579,7 +79504,7 @@ module.exports.default = module.exports;
 
 
 /***/ }),
-/* 708 */
+/* 707 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79658,7 +79583,7 @@ module.exports.default = pMap;
 
 
 /***/ }),
-/* 709 */
+/* 708 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79688,17 +79613,17 @@ module.exports = arrify;
 
 
 /***/ }),
-/* 710 */
+/* 709 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const fs = __webpack_require__(23);
-const arrayUnion = __webpack_require__(711);
-const glob = __webpack_require__(713);
-const fastGlob = __webpack_require__(718);
-const dirGlob = __webpack_require__(901);
-const gitignore = __webpack_require__(904);
+const arrayUnion = __webpack_require__(710);
+const glob = __webpack_require__(712);
+const fastGlob = __webpack_require__(717);
+const dirGlob = __webpack_require__(900);
+const gitignore = __webpack_require__(903);
 
 const DEFAULT_FILTER = () => false;
 
@@ -79843,12 +79768,12 @@ module.exports.gitignore = gitignore;
 
 
 /***/ }),
-/* 711 */
+/* 710 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-var arrayUniq = __webpack_require__(712);
+var arrayUniq = __webpack_require__(711);
 
 module.exports = function () {
 	return arrayUniq([].concat.apply([], arguments));
@@ -79856,7 +79781,7 @@ module.exports = function () {
 
 
 /***/ }),
-/* 712 */
+/* 711 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -79925,7 +79850,7 @@ if ('Set' in global) {
 
 
 /***/ }),
-/* 713 */
+/* 712 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Approach:
@@ -79974,13 +79899,13 @@ var fs = __webpack_require__(23)
 var rp = __webpack_require__(502)
 var minimatch = __webpack_require__(504)
 var Minimatch = minimatch.Minimatch
-var inherits = __webpack_require__(714)
+var inherits = __webpack_require__(713)
 var EE = __webpack_require__(379).EventEmitter
 var path = __webpack_require__(16)
 var assert = __webpack_require__(30)
 var isAbsolute = __webpack_require__(510)
-var globSync = __webpack_require__(716)
-var common = __webpack_require__(717)
+var globSync = __webpack_require__(715)
+var common = __webpack_require__(716)
 var alphasort = common.alphasort
 var alphasorti = common.alphasorti
 var setopts = common.setopts
@@ -80721,7 +80646,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
 
 
 /***/ }),
-/* 714 */
+/* 713 */
 /***/ (function(module, exports, __webpack_require__) {
 
 try {
@@ -80731,12 +80656,12 @@ try {
   module.exports = util.inherits;
 } catch (e) {
   /* istanbul ignore next */
-  module.exports = __webpack_require__(715);
+  module.exports = __webpack_require__(714);
 }
 
 
 /***/ }),
-/* 715 */
+/* 714 */
 /***/ (function(module, exports) {
 
 if (typeof Object.create === 'function') {
@@ -80769,7 +80694,7 @@ if (typeof Object.create === 'function') {
 
 
 /***/ }),
-/* 716 */
+/* 715 */
 /***/ (function(module, exports, __webpack_require__) {
 
 module.exports = globSync
@@ -80779,12 +80704,12 @@ var fs = __webpack_require__(23)
 var rp = __webpack_require__(502)
 var minimatch = __webpack_require__(504)
 var Minimatch = minimatch.Minimatch
-var Glob = __webpack_require__(713).Glob
+var Glob = __webpack_require__(712).Glob
 var util = __webpack_require__(29)
 var path = __webpack_require__(16)
 var assert = __webpack_require__(30)
 var isAbsolute = __webpack_require__(510)
-var common = __webpack_require__(717)
+var common = __webpack_require__(716)
 var alphasort = common.alphasort
 var alphasorti = common.alphasorti
 var setopts = common.setopts
@@ -81261,7 +81186,7 @@ GlobSync.prototype._makeAbs = function (f) {
 
 
 /***/ }),
-/* 717 */
+/* 716 */
 /***/ (function(module, exports, __webpack_require__) {
 
 exports.alphasort = alphasort
@@ -81507,10 +81432,10 @@ function childrenIgnored (self, path) {
 
 
 /***/ }),
-/* 718 */
+/* 717 */
 /***/ (function(module, exports, __webpack_require__) {
 
-const pkg = __webpack_require__(719);
+const pkg = __webpack_require__(718);
 
 module.exports = pkg.async;
 module.exports.default = pkg.async;
@@ -81523,19 +81448,19 @@ module.exports.generateTasks = pkg.generateTasks;
 
 
 /***/ }),
-/* 719 */
+/* 718 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var optionsManager = __webpack_require__(720);
-var taskManager = __webpack_require__(721);
-var reader_async_1 = __webpack_require__(872);
-var reader_stream_1 = __webpack_require__(896);
-var reader_sync_1 = __webpack_require__(897);
-var arrayUtils = __webpack_require__(899);
-var streamUtils = __webpack_require__(900);
+var optionsManager = __webpack_require__(719);
+var taskManager = __webpack_require__(720);
+var reader_async_1 = __webpack_require__(871);
+var reader_stream_1 = __webpack_require__(895);
+var reader_sync_1 = __webpack_require__(896);
+var arrayUtils = __webpack_require__(898);
+var streamUtils = __webpack_require__(899);
 /**
  * Synchronous API.
  */
@@ -81601,7 +81526,7 @@ function isString(source) {
 
 
 /***/ }),
-/* 720 */
+/* 719 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -81639,13 +81564,13 @@ exports.prepare = prepare;
 
 
 /***/ }),
-/* 721 */
+/* 720 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var patternUtils = __webpack_require__(722);
+var patternUtils = __webpack_require__(721);
 /**
  * Generate tasks based on parent directory of each pattern.
  */
@@ -81736,16 +81661,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask;
 
 
 /***/ }),
-/* 722 */
+/* 721 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 var path = __webpack_require__(16);
-var globParent = __webpack_require__(723);
-var isGlob = __webpack_require__(726);
-var micromatch = __webpack_require__(727);
+var globParent = __webpack_require__(722);
+var isGlob = __webpack_require__(725);
+var micromatch = __webpack_require__(726);
 var GLOBSTAR = '**';
 /**
  * Return true for static pattern.
@@ -81891,15 +81816,15 @@ exports.matchAny = matchAny;
 
 
 /***/ }),
-/* 723 */
+/* 722 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 var path = __webpack_require__(16);
-var isglob = __webpack_require__(724);
-var pathDirname = __webpack_require__(725);
+var isglob = __webpack_require__(723);
+var pathDirname = __webpack_require__(724);
 var isWin32 = __webpack_require__(11).platform() === 'win32';
 
 module.exports = function globParent(str) {
@@ -81922,7 +81847,7 @@ module.exports = function globParent(str) {
 
 
 /***/ }),
-/* 724 */
+/* 723 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /*!
@@ -81932,7 +81857,7 @@ module.exports = function globParent(str) {
  * Licensed under the MIT License.
  */
 
-var isExtglob = __webpack_require__(605);
+var isExtglob = __webpack_require__(604);
 
 module.exports = function isGlob(str) {
   if (typeof str !== 'string' || str === '') {
@@ -81953,7 +81878,7 @@ module.exports = function isGlob(str) {
 
 
 /***/ }),
-/* 725 */
+/* 724 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -82103,7 +82028,7 @@ module.exports.win32 = win32;
 
 
 /***/ }),
-/* 726 */
+/* 725 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /*!
@@ -82113,7 +82038,7 @@ module.exports.win32 = win32;
  * Released under the MIT License.
  */
 
-var isExtglob = __webpack_require__(605);
+var isExtglob = __webpack_require__(604);
 var chars = { '{': '}', '(': ')', '[': ']'};
 
 module.exports = function isGlob(str, options) {
@@ -82155,7 +82080,7 @@ module.exports = function isGlob(str, options) {
 
 
 /***/ }),
-/* 727 */
+/* 726 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -82166,18 +82091,18 @@ module.exports = function isGlob(str, options) {
  */
 
 var util = __webpack_require__(29);
-var braces = __webpack_require__(728);
-var toRegex = __webpack_require__(830);
-var extend = __webpack_require__(838);
+var braces = __webpack_require__(727);
+var toRegex = __webpack_require__(829);
+var extend = __webpack_require__(837);
 
 /**
  * Local dependencies
  */
 
-var compilers = __webpack_require__(841);
-var parsers = __webpack_require__(868);
-var cache = __webpack_require__(869);
-var utils = __webpack_require__(870);
+var compilers = __webpack_require__(840);
+var parsers = __webpack_require__(867);
+var cache = __webpack_require__(868);
+var utils = __webpack_require__(869);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -83039,7 +82964,7 @@ module.exports = micromatch;
 
 
 /***/ }),
-/* 728 */
+/* 727 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -83049,18 +82974,18 @@ module.exports = micromatch;
  * Module dependencies
  */
 
-var toRegex = __webpack_require__(729);
-var unique = __webpack_require__(741);
-var extend = __webpack_require__(738);
+var toRegex = __webpack_require__(728);
+var unique = __webpack_require__(740);
+var extend = __webpack_require__(737);
 
 /**
  * Local dependencies
  */
 
-var compilers = __webpack_require__(742);
-var parsers = __webpack_require__(757);
-var Braces = __webpack_require__(767);
-var utils = __webpack_require__(743);
+var compilers = __webpack_require__(741);
+var parsers = __webpack_require__(756);
+var Braces = __webpack_require__(766);
+var utils = __webpack_require__(742);
 var MAX_LENGTH = 1024 * 64;
 var cache = {};
 
@@ -83364,15 +83289,15 @@ module.exports = braces;
 
 
 /***/ }),
-/* 729 */
+/* 728 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var define = __webpack_require__(730);
-var extend = __webpack_require__(738);
-var not = __webpack_require__(740);
+var define = __webpack_require__(729);
+var extend = __webpack_require__(737);
+var not = __webpack_require__(739);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -83519,7 +83444,7 @@ module.exports.makeRe = makeRe;
 
 
 /***/ }),
-/* 730 */
+/* 729 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -83532,7 +83457,7 @@ module.exports.makeRe = makeRe;
 
 
 
-var isDescriptor = __webpack_require__(731);
+var isDescriptor = __webpack_require__(730);
 
 module.exports = function defineProperty(obj, prop, val) {
   if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -83557,7 +83482,7 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 /***/ }),
-/* 731 */
+/* 730 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -83570,9 +83495,9 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 
-var typeOf = __webpack_require__(732);
-var isAccessor = __webpack_require__(733);
-var isData = __webpack_require__(736);
+var typeOf = __webpack_require__(731);
+var isAccessor = __webpack_require__(732);
+var isData = __webpack_require__(735);
 
 module.exports = function isDescriptor(obj, key) {
   if (typeOf(obj) !== 'object') {
@@ -83586,7 +83511,7 @@ module.exports = function isDescriptor(obj, key) {
 
 
 /***/ }),
-/* 732 */
+/* 731 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -83739,7 +83664,7 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 733 */
+/* 732 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -83752,7 +83677,7 @@ function isBuffer(val) {
 
 
 
-var typeOf = __webpack_require__(734);
+var typeOf = __webpack_require__(733);
 
 // accessor descriptor properties
 var accessor = {
@@ -83815,10 +83740,10 @@ module.exports = isAccessorDescriptor;
 
 
 /***/ }),
-/* 734 */
+/* 733 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(734);
 var toString = Object.prototype.toString;
 
 /**
@@ -83937,7 +83862,7 @@ module.exports = function kindOf(val) {
 
 
 /***/ }),
-/* 735 */
+/* 734 */
 /***/ (function(module, exports) {
 
 /*!
@@ -83964,7 +83889,7 @@ function isSlowBuffer (obj) {
 
 
 /***/ }),
-/* 736 */
+/* 735 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -83977,7 +83902,7 @@ function isSlowBuffer (obj) {
 
 
 
-var typeOf = __webpack_require__(737);
+var typeOf = __webpack_require__(736);
 
 // data descriptor properties
 var data = {
@@ -84026,10 +83951,10 @@ module.exports = isDataDescriptor;
 
 
 /***/ }),
-/* 737 */
+/* 736 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(734);
 var toString = Object.prototype.toString;
 
 /**
@@ -84148,13 +84073,13 @@ module.exports = function kindOf(val) {
 
 
 /***/ }),
-/* 738 */
+/* 737 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isObject = __webpack_require__(739);
+var isObject = __webpack_require__(738);
 
 module.exports = function extend(o/*, objects*/) {
   if (!isObject(o)) { o = {}; }
@@ -84188,7 +84113,7 @@ function hasOwn(obj, key) {
 
 
 /***/ }),
-/* 739 */
+/* 738 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -84208,13 +84133,13 @@ module.exports = function isExtendable(val) {
 
 
 /***/ }),
-/* 740 */
+/* 739 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var extend = __webpack_require__(738);
+var extend = __webpack_require__(737);
 
 /**
  * The main export is a function that takes a `pattern` string and an `options` object.
@@ -84281,7 +84206,7 @@ module.exports = toRegex;
 
 
 /***/ }),
-/* 741 */
+/* 740 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -84331,13 +84256,13 @@ module.exports.immutable = function uniqueImmutable(arr) {
 
 
 /***/ }),
-/* 742 */
+/* 741 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var utils = __webpack_require__(743);
+var utils = __webpack_require__(742);
 
 module.exports = function(braces, options) {
   braces.compiler
@@ -84620,25 +84545,25 @@ function hasQueue(node) {
 
 
 /***/ }),
-/* 743 */
+/* 742 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var splitString = __webpack_require__(744);
+var splitString = __webpack_require__(743);
 var utils = module.exports;
 
 /**
  * Module dependencies
  */
 
-utils.extend = __webpack_require__(738);
-utils.flatten = __webpack_require__(750);
-utils.isObject = __webpack_require__(748);
-utils.fillRange = __webpack_require__(751);
-utils.repeat = __webpack_require__(756);
-utils.unique = __webpack_require__(741);
+utils.extend = __webpack_require__(737);
+utils.flatten = __webpack_require__(749);
+utils.isObject = __webpack_require__(747);
+utils.fillRange = __webpack_require__(750);
+utils.repeat = __webpack_require__(755);
+utils.unique = __webpack_require__(740);
 
 utils.define = function(obj, key, val) {
   Object.defineProperty(obj, key, {
@@ -84970,7 +84895,7 @@ utils.escapeRegex = function(str) {
 
 
 /***/ }),
-/* 744 */
+/* 743 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -84983,7 +84908,7 @@ utils.escapeRegex = function(str) {
 
 
 
-var extend = __webpack_require__(745);
+var extend = __webpack_require__(744);
 
 module.exports = function(str, options, fn) {
   if (typeof str !== 'string') {
@@ -85148,14 +85073,14 @@ function keepEscaping(opts, str, idx) {
 
 
 /***/ }),
-/* 745 */
+/* 744 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isExtendable = __webpack_require__(746);
-var assignSymbols = __webpack_require__(749);
+var isExtendable = __webpack_require__(745);
+var assignSymbols = __webpack_require__(748);
 
 module.exports = Object.assign || function(obj/*, objects*/) {
   if (obj === null || typeof obj === 'undefined') {
@@ -85215,7 +85140,7 @@ function isEnum(obj, key) {
 
 
 /***/ }),
-/* 746 */
+/* 745 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85228,7 +85153,7 @@ function isEnum(obj, key) {
 
 
 
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(746);
 
 module.exports = function isExtendable(val) {
   return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -85236,7 +85161,7 @@ module.exports = function isExtendable(val) {
 
 
 /***/ }),
-/* 747 */
+/* 746 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85249,7 +85174,7 @@ module.exports = function isExtendable(val) {
 
 
 
-var isObject = __webpack_require__(748);
+var isObject = __webpack_require__(747);
 
 function isObjectObject(o) {
   return isObject(o) === true
@@ -85280,7 +85205,7 @@ module.exports = function isPlainObject(o) {
 
 
 /***/ }),
-/* 748 */
+/* 747 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85299,7 +85224,7 @@ module.exports = function isObject(val) {
 
 
 /***/ }),
-/* 749 */
+/* 748 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85346,7 +85271,7 @@ module.exports = function(receiver, objects) {
 
 
 /***/ }),
-/* 750 */
+/* 749 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85375,7 +85300,7 @@ function flat(arr, res) {
 
 
 /***/ }),
-/* 751 */
+/* 750 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85389,10 +85314,10 @@ function flat(arr, res) {
 
 
 var util = __webpack_require__(29);
-var isNumber = __webpack_require__(752);
-var extend = __webpack_require__(738);
-var repeat = __webpack_require__(754);
-var toRegex = __webpack_require__(755);
+var isNumber = __webpack_require__(751);
+var extend = __webpack_require__(737);
+var repeat = __webpack_require__(753);
+var toRegex = __webpack_require__(754);
 
 /**
  * Return a range of numbers or letters.
@@ -85590,7 +85515,7 @@ module.exports = fillRange;
 
 
 /***/ }),
-/* 752 */
+/* 751 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85603,7 +85528,7 @@ module.exports = fillRange;
 
 
 
-var typeOf = __webpack_require__(753);
+var typeOf = __webpack_require__(752);
 
 module.exports = function isNumber(num) {
   var type = typeOf(num);
@@ -85619,10 +85544,10 @@ module.exports = function isNumber(num) {
 
 
 /***/ }),
-/* 753 */
+/* 752 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(734);
 var toString = Object.prototype.toString;
 
 /**
@@ -85741,7 +85666,7 @@ module.exports = function kindOf(val) {
 
 
 /***/ }),
-/* 754 */
+/* 753 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85818,7 +85743,7 @@ function repeat(str, num) {
 
 
 /***/ }),
-/* 755 */
+/* 754 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -85831,8 +85756,8 @@ function repeat(str, num) {
 
 
 
-var repeat = __webpack_require__(754);
-var isNumber = __webpack_require__(752);
+var repeat = __webpack_require__(753);
+var isNumber = __webpack_require__(751);
 var cache = {};
 
 function toRegexRange(min, max, options) {
@@ -86119,7 +86044,7 @@ module.exports = toRegexRange;
 
 
 /***/ }),
-/* 756 */
+/* 755 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -86144,14 +86069,14 @@ module.exports = function repeat(ele, num) {
 
 
 /***/ }),
-/* 757 */
+/* 756 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var Node = __webpack_require__(758);
-var utils = __webpack_require__(743);
+var Node = __webpack_require__(757);
+var utils = __webpack_require__(742);
 
 /**
  * Braces parsers
@@ -86511,15 +86436,15 @@ function concatNodes(pos, node, parent, options) {
 
 
 /***/ }),
-/* 758 */
+/* 757 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isObject = __webpack_require__(748);
-var define = __webpack_require__(759);
-var utils = __webpack_require__(766);
+var isObject = __webpack_require__(747);
+var define = __webpack_require__(758);
+var utils = __webpack_require__(765);
 var ownNames;
 
 /**
@@ -87010,7 +86935,7 @@ exports = module.exports = Node;
 
 
 /***/ }),
-/* 759 */
+/* 758 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -87023,7 +86948,7 @@ exports = module.exports = Node;
 
 
 
-var isDescriptor = __webpack_require__(760);
+var isDescriptor = __webpack_require__(759);
 
 module.exports = function defineProperty(obj, prop, val) {
   if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -87048,7 +86973,7 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 /***/ }),
-/* 760 */
+/* 759 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -87061,9 +86986,9 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 
-var typeOf = __webpack_require__(761);
-var isAccessor = __webpack_require__(762);
-var isData = __webpack_require__(764);
+var typeOf = __webpack_require__(760);
+var isAccessor = __webpack_require__(761);
+var isData = __webpack_require__(763);
 
 module.exports = function isDescriptor(obj, key) {
   if (typeOf(obj) !== 'object') {
@@ -87077,7 +87002,7 @@ module.exports = function isDescriptor(obj, key) {
 
 
 /***/ }),
-/* 761 */
+/* 760 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -87212,7 +87137,7 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 762 */
+/* 761 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -87225,7 +87150,7 @@ function isBuffer(val) {
 
 
 
-var typeOf = __webpack_require__(763);
+var typeOf = __webpack_require__(762);
 
 // accessor descriptor properties
 var accessor = {
@@ -87288,7 +87213,7 @@ module.exports = isAccessorDescriptor;
 
 
 /***/ }),
-/* 763 */
+/* 762 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -87423,7 +87348,7 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 764 */
+/* 763 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -87436,7 +87361,7 @@ function isBuffer(val) {
 
 
 
-var typeOf = __webpack_require__(765);
+var typeOf = __webpack_require__(764);
 
 module.exports = function isDataDescriptor(obj, prop) {
   // data descriptor properties
@@ -87479,7 +87404,7 @@ module.exports = function isDataDescriptor(obj, prop) {
 
 
 /***/ }),
-/* 765 */
+/* 764 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -87614,13 +87539,13 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 766 */
+/* 765 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var typeOf = __webpack_require__(753);
+var typeOf = __webpack_require__(752);
 var utils = module.exports;
 
 /**
@@ -88640,17 +88565,17 @@ function assert(val, message) {
 
 
 /***/ }),
-/* 767 */
+/* 766 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var extend = __webpack_require__(738);
-var Snapdragon = __webpack_require__(768);
-var compilers = __webpack_require__(742);
-var parsers = __webpack_require__(757);
-var utils = __webpack_require__(743);
+var extend = __webpack_require__(737);
+var Snapdragon = __webpack_require__(767);
+var compilers = __webpack_require__(741);
+var parsers = __webpack_require__(756);
+var utils = __webpack_require__(742);
 
 /**
  * Customize Snapdragon parser and renderer
@@ -88751,17 +88676,17 @@ module.exports = Braces;
 
 
 /***/ }),
-/* 768 */
+/* 767 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var Base = __webpack_require__(769);
-var define = __webpack_require__(730);
-var Compiler = __webpack_require__(798);
-var Parser = __webpack_require__(827);
-var utils = __webpack_require__(807);
+var Base = __webpack_require__(768);
+var define = __webpack_require__(729);
+var Compiler = __webpack_require__(797);
+var Parser = __webpack_require__(826);
+var utils = __webpack_require__(806);
 var regexCache = {};
 var cache = {};
 
@@ -88932,20 +88857,20 @@ module.exports.Parser = Parser;
 
 
 /***/ }),
-/* 769 */
+/* 768 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 var util = __webpack_require__(29);
-var define = __webpack_require__(770);
-var CacheBase = __webpack_require__(771);
-var Emitter = __webpack_require__(772);
-var isObject = __webpack_require__(748);
-var merge = __webpack_require__(789);
-var pascal = __webpack_require__(792);
-var cu = __webpack_require__(793);
+var define = __webpack_require__(769);
+var CacheBase = __webpack_require__(770);
+var Emitter = __webpack_require__(771);
+var isObject = __webpack_require__(747);
+var merge = __webpack_require__(788);
+var pascal = __webpack_require__(791);
+var cu = __webpack_require__(792);
 
 /**
  * Optionally define a custom `cache` namespace to use.
@@ -89374,7 +89299,7 @@ module.exports.namespace = namespace;
 
 
 /***/ }),
-/* 770 */
+/* 769 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -89387,7 +89312,7 @@ module.exports.namespace = namespace;
 
 
 
-var isDescriptor = __webpack_require__(760);
+var isDescriptor = __webpack_require__(759);
 
 module.exports = function defineProperty(obj, prop, val) {
   if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -89412,21 +89337,21 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 /***/ }),
-/* 771 */
+/* 770 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isObject = __webpack_require__(748);
-var Emitter = __webpack_require__(772);
-var visit = __webpack_require__(773);
-var toPath = __webpack_require__(776);
-var union = __webpack_require__(777);
-var del = __webpack_require__(781);
-var get = __webpack_require__(779);
-var has = __webpack_require__(786);
-var set = __webpack_require__(780);
+var isObject = __webpack_require__(747);
+var Emitter = __webpack_require__(771);
+var visit = __webpack_require__(772);
+var toPath = __webpack_require__(775);
+var union = __webpack_require__(776);
+var del = __webpack_require__(780);
+var get = __webpack_require__(778);
+var has = __webpack_require__(785);
+var set = __webpack_require__(779);
 
 /**
  * Create a `Cache` constructor that when instantiated will
@@ -89680,7 +89605,7 @@ module.exports.namespace = namespace;
 
 
 /***/ }),
-/* 772 */
+/* 771 */
 /***/ (function(module, exports, __webpack_require__) {
 
 
@@ -89849,7 +89774,7 @@ Emitter.prototype.hasListeners = function(event){
 
 
 /***/ }),
-/* 773 */
+/* 772 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -89862,8 +89787,8 @@ Emitter.prototype.hasListeners = function(event){
 
 
 
-var visit = __webpack_require__(774);
-var mapVisit = __webpack_require__(775);
+var visit = __webpack_require__(773);
+var mapVisit = __webpack_require__(774);
 
 module.exports = function(collection, method, val) {
   var result;
@@ -89886,7 +89811,7 @@ module.exports = function(collection, method, val) {
 
 
 /***/ }),
-/* 774 */
+/* 773 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -89899,7 +89824,7 @@ module.exports = function(collection, method, val) {
 
 
 
-var isObject = __webpack_require__(748);
+var isObject = __webpack_require__(747);
 
 module.exports = function visit(thisArg, method, target, val) {
   if (!isObject(thisArg) && typeof thisArg !== 'function') {
@@ -89926,14 +89851,14 @@ module.exports = function visit(thisArg, method, target, val) {
 
 
 /***/ }),
-/* 775 */
+/* 774 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 var util = __webpack_require__(29);
-var visit = __webpack_require__(774);
+var visit = __webpack_require__(773);
 
 /**
  * Map `visit` over an array of objects.
@@ -89970,7 +89895,7 @@ function isObject(val) {
 
 
 /***/ }),
-/* 776 */
+/* 775 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -89983,7 +89908,7 @@ function isObject(val) {
 
 
 
-var typeOf = __webpack_require__(753);
+var typeOf = __webpack_require__(752);
 
 module.exports = function toPath(args) {
   if (typeOf(args) !== 'arguments') {
@@ -90010,16 +89935,16 @@ function filter(arr) {
 
 
 /***/ }),
-/* 777 */
+/* 776 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isObject = __webpack_require__(739);
-var union = __webpack_require__(778);
-var get = __webpack_require__(779);
-var set = __webpack_require__(780);
+var isObject = __webpack_require__(738);
+var union = __webpack_require__(777);
+var get = __webpack_require__(778);
+var set = __webpack_require__(779);
 
 module.exports = function unionValue(obj, prop, value) {
   if (!isObject(obj)) {
@@ -90047,7 +89972,7 @@ function arrayify(val) {
 
 
 /***/ }),
-/* 778 */
+/* 777 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90083,7 +90008,7 @@ module.exports = function union(init) {
 
 
 /***/ }),
-/* 779 */
+/* 778 */
 /***/ (function(module, exports) {
 
 /*!
@@ -90139,7 +90064,7 @@ function toString(val) {
 
 
 /***/ }),
-/* 780 */
+/* 779 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90152,10 +90077,10 @@ function toString(val) {
 
 
 
-var split = __webpack_require__(744);
-var extend = __webpack_require__(738);
-var isPlainObject = __webpack_require__(747);
-var isObject = __webpack_require__(739);
+var split = __webpack_require__(743);
+var extend = __webpack_require__(737);
+var isPlainObject = __webpack_require__(746);
+var isObject = __webpack_require__(738);
 
 module.exports = function(obj, prop, val) {
   if (!isObject(obj)) {
@@ -90201,7 +90126,7 @@ function isValidKey(key) {
 
 
 /***/ }),
-/* 781 */
+/* 780 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90214,8 +90139,8 @@ function isValidKey(key) {
 
 
 
-var isObject = __webpack_require__(748);
-var has = __webpack_require__(782);
+var isObject = __webpack_require__(747);
+var has = __webpack_require__(781);
 
 module.exports = function unset(obj, prop) {
   if (!isObject(obj)) {
@@ -90240,7 +90165,7 @@ module.exports = function unset(obj, prop) {
 
 
 /***/ }),
-/* 782 */
+/* 781 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90253,9 +90178,9 @@ module.exports = function unset(obj, prop) {
 
 
 
-var isObject = __webpack_require__(783);
-var hasValues = __webpack_require__(785);
-var get = __webpack_require__(779);
+var isObject = __webpack_require__(782);
+var hasValues = __webpack_require__(784);
+var get = __webpack_require__(778);
 
 module.exports = function(obj, prop, noZero) {
   if (isObject(obj)) {
@@ -90266,7 +90191,7 @@ module.exports = function(obj, prop, noZero) {
 
 
 /***/ }),
-/* 783 */
+/* 782 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90279,7 +90204,7 @@ module.exports = function(obj, prop, noZero) {
 
 
 
-var isArray = __webpack_require__(784);
+var isArray = __webpack_require__(783);
 
 module.exports = function isObject(val) {
   return val != null && typeof val === 'object' && isArray(val) === false;
@@ -90287,7 +90212,7 @@ module.exports = function isObject(val) {
 
 
 /***/ }),
-/* 784 */
+/* 783 */
 /***/ (function(module, exports) {
 
 var toString = {}.toString;
@@ -90298,7 +90223,7 @@ module.exports = Array.isArray || function (arr) {
 
 
 /***/ }),
-/* 785 */
+/* 784 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90341,7 +90266,7 @@ module.exports = function hasValue(o, noZero) {
 
 
 /***/ }),
-/* 786 */
+/* 785 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90354,9 +90279,9 @@ module.exports = function hasValue(o, noZero) {
 
 
 
-var isObject = __webpack_require__(748);
-var hasValues = __webpack_require__(787);
-var get = __webpack_require__(779);
+var isObject = __webpack_require__(747);
+var hasValues = __webpack_require__(786);
+var get = __webpack_require__(778);
 
 module.exports = function(val, prop) {
   return hasValues(isObject(val) && prop ? get(val, prop) : val);
@@ -90364,7 +90289,7 @@ module.exports = function(val, prop) {
 
 
 /***/ }),
-/* 787 */
+/* 786 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90377,8 +90302,8 @@ module.exports = function(val, prop) {
 
 
 
-var typeOf = __webpack_require__(788);
-var isNumber = __webpack_require__(752);
+var typeOf = __webpack_require__(787);
+var isNumber = __webpack_require__(751);
 
 module.exports = function hasValue(val) {
   // is-number checks for NaN and other edge cases
@@ -90431,10 +90356,10 @@ module.exports = function hasValue(val) {
 
 
 /***/ }),
-/* 788 */
+/* 787 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(734);
 var toString = Object.prototype.toString;
 
 /**
@@ -90556,14 +90481,14 @@ module.exports = function kindOf(val) {
 
 
 /***/ }),
-/* 789 */
+/* 788 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isExtendable = __webpack_require__(790);
-var forIn = __webpack_require__(791);
+var isExtendable = __webpack_require__(789);
+var forIn = __webpack_require__(790);
 
 function mixinDeep(target, objects) {
   var len = arguments.length, i = 0;
@@ -90627,7 +90552,7 @@ module.exports = mixinDeep;
 
 
 /***/ }),
-/* 790 */
+/* 789 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90640,7 +90565,7 @@ module.exports = mixinDeep;
 
 
 
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(746);
 
 module.exports = function isExtendable(val) {
   return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -90648,7 +90573,7 @@ module.exports = function isExtendable(val) {
 
 
 /***/ }),
-/* 791 */
+/* 790 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -90671,7 +90596,7 @@ module.exports = function forIn(obj, fn, thisArg) {
 
 
 /***/ }),
-/* 792 */
+/* 791 */
 /***/ (function(module, exports) {
 
 /*!
@@ -90698,14 +90623,14 @@ module.exports = pascalcase;
 
 
 /***/ }),
-/* 793 */
+/* 792 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 var util = __webpack_require__(29);
-var utils = __webpack_require__(794);
+var utils = __webpack_require__(793);
 
 /**
  * Expose class utils
@@ -91070,7 +90995,7 @@ cu.bubble = function(Parent, events) {
 
 
 /***/ }),
-/* 794 */
+/* 793 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -91084,10 +91009,10 @@ var utils = {};
  * Lazily required module dependencies
  */
 
-utils.union = __webpack_require__(778);
-utils.define = __webpack_require__(730);
-utils.isObj = __webpack_require__(748);
-utils.staticExtend = __webpack_require__(795);
+utils.union = __webpack_require__(777);
+utils.define = __webpack_require__(729);
+utils.isObj = __webpack_require__(747);
+utils.staticExtend = __webpack_require__(794);
 
 
 /**
@@ -91098,7 +91023,7 @@ module.exports = utils;
 
 
 /***/ }),
-/* 795 */
+/* 794 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -91111,8 +91036,8 @@ module.exports = utils;
 
 
 
-var copy = __webpack_require__(796);
-var define = __webpack_require__(730);
+var copy = __webpack_require__(795);
+var define = __webpack_require__(729);
 var util = __webpack_require__(29);
 
 /**
@@ -91195,15 +91120,15 @@ module.exports = extend;
 
 
 /***/ }),
-/* 796 */
+/* 795 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var typeOf = __webpack_require__(753);
-var copyDescriptor = __webpack_require__(797);
-var define = __webpack_require__(730);
+var typeOf = __webpack_require__(752);
+var copyDescriptor = __webpack_require__(796);
+var define = __webpack_require__(729);
 
 /**
  * Copy static properties, prototype properties, and descriptors from one object to another.
@@ -91376,7 +91301,7 @@ module.exports.has = has;
 
 
 /***/ }),
-/* 797 */
+/* 796 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -91464,16 +91389,16 @@ function isObject(val) {
 
 
 /***/ }),
-/* 798 */
+/* 797 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var use = __webpack_require__(799);
-var define = __webpack_require__(730);
-var debug = __webpack_require__(801)('snapdragon:compiler');
-var utils = __webpack_require__(807);
+var use = __webpack_require__(798);
+var define = __webpack_require__(729);
+var debug = __webpack_require__(800)('snapdragon:compiler');
+var utils = __webpack_require__(806);
 
 /**
  * Create a new `Compiler` with the given `options`.
@@ -91627,7 +91552,7 @@ Compiler.prototype = {
 
     // source map support
     if (opts.sourcemap) {
-      var sourcemaps = __webpack_require__(826);
+      var sourcemaps = __webpack_require__(825);
       sourcemaps(this);
       this.mapVisit(this.ast.nodes);
       this.applySourceMaps();
@@ -91648,7 +91573,7 @@ module.exports = Compiler;
 
 
 /***/ }),
-/* 799 */
+/* 798 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -91661,7 +91586,7 @@ module.exports = Compiler;
 
 
 
-var utils = __webpack_require__(800);
+var utils = __webpack_require__(799);
 
 module.exports = function base(app, opts) {
   if (!utils.isObject(app) && typeof app !== 'function') {
@@ -91776,7 +91701,7 @@ module.exports = function base(app, opts) {
 
 
 /***/ }),
-/* 800 */
+/* 799 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -91790,8 +91715,8 @@ var utils = {};
  * Lazily required module dependencies
  */
 
-utils.define = __webpack_require__(730);
-utils.isObject = __webpack_require__(748);
+utils.define = __webpack_require__(729);
+utils.isObject = __webpack_require__(747);
 
 
 utils.isString = function(val) {
@@ -91806,7 +91731,7 @@ module.exports = utils;
 
 
 /***/ }),
-/* 801 */
+/* 800 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /**
@@ -91815,14 +91740,14 @@ module.exports = utils;
  */
 
 if (typeof process !== 'undefined' && process.type === 'renderer') {
-  module.exports = __webpack_require__(802);
+  module.exports = __webpack_require__(801);
 } else {
-  module.exports = __webpack_require__(805);
+  module.exports = __webpack_require__(804);
 }
 
 
 /***/ }),
-/* 802 */
+/* 801 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /**
@@ -91831,7 +91756,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') {
  * Expose `debug()` as the module.
  */
 
-exports = module.exports = __webpack_require__(803);
+exports = module.exports = __webpack_require__(802);
 exports.log = log;
 exports.formatArgs = formatArgs;
 exports.save = save;
@@ -92013,7 +91938,7 @@ function localstorage() {
 
 
 /***/ }),
-/* 803 */
+/* 802 */
 /***/ (function(module, exports, __webpack_require__) {
 
 
@@ -92029,7 +91954,7 @@ exports.coerce = coerce;
 exports.disable = disable;
 exports.enable = enable;
 exports.enabled = enabled;
-exports.humanize = __webpack_require__(804);
+exports.humanize = __webpack_require__(803);
 
 /**
  * The currently active debug mode names, and names to skip.
@@ -92221,7 +92146,7 @@ function coerce(val) {
 
 
 /***/ }),
-/* 804 */
+/* 803 */
 /***/ (function(module, exports) {
 
 /**
@@ -92379,7 +92304,7 @@ function plural(ms, n, name) {
 
 
 /***/ }),
-/* 805 */
+/* 804 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /**
@@ -92395,7 +92320,7 @@ var util = __webpack_require__(29);
  * Expose `debug()` as the module.
  */
 
-exports = module.exports = __webpack_require__(803);
+exports = module.exports = __webpack_require__(802);
 exports.init = init;
 exports.log = log;
 exports.formatArgs = formatArgs;
@@ -92574,7 +92499,7 @@ function createWritableStdioStream (fd) {
 
     case 'PIPE':
     case 'TCP':
-      var net = __webpack_require__(806);
+      var net = __webpack_require__(805);
       stream = new net.Socket({
         fd: fd,
         readable: false,
@@ -92633,13 +92558,13 @@ exports.enable(load());
 
 
 /***/ }),
-/* 806 */
+/* 805 */
 /***/ (function(module, exports) {
 
 module.exports = require("net");
 
 /***/ }),
-/* 807 */
+/* 806 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -92649,9 +92574,9 @@ module.exports = require("net");
  * Module dependencies
  */
 
-exports.extend = __webpack_require__(738);
-exports.SourceMap = __webpack_require__(808);
-exports.sourceMapResolve = __webpack_require__(819);
+exports.extend = __webpack_require__(737);
+exports.SourceMap = __webpack_require__(807);
+exports.sourceMapResolve = __webpack_require__(818);
 
 /**
  * Convert backslash in the given string to forward slashes
@@ -92694,7 +92619,7 @@ exports.last = function(arr, n) {
 
 
 /***/ }),
-/* 808 */
+/* 807 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /*
@@ -92702,13 +92627,13 @@ exports.last = function(arr, n) {
  * Licensed under the New BSD license. See LICENSE.txt or:
  * http://opensource.org/licenses/BSD-3-Clause
  */
-exports.SourceMapGenerator = __webpack_require__(809).SourceMapGenerator;
-exports.SourceMapConsumer = __webpack_require__(815).SourceMapConsumer;
-exports.SourceNode = __webpack_require__(818).SourceNode;
+exports.SourceMapGenerator = __webpack_require__(808).SourceMapGenerator;
+exports.SourceMapConsumer = __webpack_require__(814).SourceMapConsumer;
+exports.SourceNode = __webpack_require__(817).SourceNode;
 
 
 /***/ }),
-/* 809 */
+/* 808 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -92718,10 +92643,10 @@ exports.SourceNode = __webpack_require__(818).SourceNode;
  * http://opensource.org/licenses/BSD-3-Clause
  */
 
-var base64VLQ = __webpack_require__(810);
-var util = __webpack_require__(812);
-var ArraySet = __webpack_require__(813).ArraySet;
-var MappingList = __webpack_require__(814).MappingList;
+var base64VLQ = __webpack_require__(809);
+var util = __webpack_require__(811);
+var ArraySet = __webpack_require__(812).ArraySet;
+var MappingList = __webpack_require__(813).MappingList;
 
 /**
  * An instance of the SourceMapGenerator represents a source map which is
@@ -93130,7 +93055,7 @@ exports.SourceMapGenerator = SourceMapGenerator;
 
 
 /***/ }),
-/* 810 */
+/* 809 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93170,7 +93095,7 @@ exports.SourceMapGenerator = SourceMapGenerator;
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-var base64 = __webpack_require__(811);
+var base64 = __webpack_require__(810);
 
 // A single base 64 digit can contain 6 bits of data. For the base 64 variable
 // length quantities we use in the source map spec, the first bit is the sign,
@@ -93276,7 +93201,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) {
 
 
 /***/ }),
-/* 811 */
+/* 810 */
 /***/ (function(module, exports) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93349,7 +93274,7 @@ exports.decode = function (charCode) {
 
 
 /***/ }),
-/* 812 */
+/* 811 */
 /***/ (function(module, exports) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93772,7 +93697,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate
 
 
 /***/ }),
-/* 813 */
+/* 812 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93782,7 +93707,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate
  * http://opensource.org/licenses/BSD-3-Clause
  */
 
-var util = __webpack_require__(812);
+var util = __webpack_require__(811);
 var has = Object.prototype.hasOwnProperty;
 var hasNativeMap = typeof Map !== "undefined";
 
@@ -93899,7 +93824,7 @@ exports.ArraySet = ArraySet;
 
 
 /***/ }),
-/* 814 */
+/* 813 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93909,7 +93834,7 @@ exports.ArraySet = ArraySet;
  * http://opensource.org/licenses/BSD-3-Clause
  */
 
-var util = __webpack_require__(812);
+var util = __webpack_require__(811);
 
 /**
  * Determine whether mappingB is after mappingA with respect to generated
@@ -93984,7 +93909,7 @@ exports.MappingList = MappingList;
 
 
 /***/ }),
-/* 815 */
+/* 814 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93994,11 +93919,11 @@ exports.MappingList = MappingList;
  * http://opensource.org/licenses/BSD-3-Clause
  */
 
-var util = __webpack_require__(812);
-var binarySearch = __webpack_require__(816);
-var ArraySet = __webpack_require__(813).ArraySet;
-var base64VLQ = __webpack_require__(810);
-var quickSort = __webpack_require__(817).quickSort;
+var util = __webpack_require__(811);
+var binarySearch = __webpack_require__(815);
+var ArraySet = __webpack_require__(812).ArraySet;
+var base64VLQ = __webpack_require__(809);
+var quickSort = __webpack_require__(816).quickSort;
 
 function SourceMapConsumer(aSourceMap) {
   var sourceMap = aSourceMap;
@@ -95072,7 +94997,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer;
 
 
 /***/ }),
-/* 816 */
+/* 815 */
 /***/ (function(module, exports) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -95189,7 +95114,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) {
 
 
 /***/ }),
-/* 817 */
+/* 816 */
 /***/ (function(module, exports) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -95309,7 +95234,7 @@ exports.quickSort = function (ary, comparator) {
 
 
 /***/ }),
-/* 818 */
+/* 817 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* -*- Mode: js; js-indent-level: 2; -*- */
@@ -95319,8 +95244,8 @@ exports.quickSort = function (ary, comparator) {
  * http://opensource.org/licenses/BSD-3-Clause
  */
 
-var SourceMapGenerator = __webpack_require__(809).SourceMapGenerator;
-var util = __webpack_require__(812);
+var SourceMapGenerator = __webpack_require__(808).SourceMapGenerator;
+var util = __webpack_require__(811);
 
 // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
 // operating systems these days (capturing the result).
@@ -95728,17 +95653,17 @@ exports.SourceNode = SourceNode;
 
 
 /***/ }),
-/* 819 */
+/* 818 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Copyright 2014, 2015, 2016, 2017 Simon Lydell
 // X11 (“MIT”) Licensed. (See LICENSE.)
 
-var sourceMappingURL   = __webpack_require__(820)
-var resolveUrl         = __webpack_require__(821)
-var decodeUriComponent = __webpack_require__(822)
-var urix               = __webpack_require__(824)
-var atob               = __webpack_require__(825)
+var sourceMappingURL   = __webpack_require__(819)
+var resolveUrl         = __webpack_require__(820)
+var decodeUriComponent = __webpack_require__(821)
+var urix               = __webpack_require__(823)
+var atob               = __webpack_require__(824)
 
 
 
@@ -96036,7 +95961,7 @@ module.exports = {
 
 
 /***/ }),
-/* 820 */
+/* 819 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell
@@ -96099,7 +96024,7 @@ void (function(root, factory) {
 
 
 /***/ }),
-/* 821 */
+/* 820 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Copyright 2014 Simon Lydell
@@ -96117,13 +96042,13 @@ module.exports = resolveUrl
 
 
 /***/ }),
-/* 822 */
+/* 821 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Copyright 2017 Simon Lydell
 // X11 (“MIT”) Licensed. (See LICENSE.)
 
-var decodeUriComponent = __webpack_require__(823)
+var decodeUriComponent = __webpack_require__(822)
 
 function customDecodeUriComponent(string) {
   // `decodeUriComponent` turns `+` into ` `, but that's not wanted.
@@ -96134,7 +96059,7 @@ module.exports = customDecodeUriComponent
 
 
 /***/ }),
-/* 823 */
+/* 822 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -96235,7 +96160,7 @@ module.exports = function (encodedURI) {
 
 
 /***/ }),
-/* 824 */
+/* 823 */
 /***/ (function(module, exports, __webpack_require__) {
 
 // Copyright 2014 Simon Lydell
@@ -96258,7 +96183,7 @@ module.exports = urix
 
 
 /***/ }),
-/* 825 */
+/* 824 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -96272,7 +96197,7 @@ module.exports = atob.atob = atob;
 
 
 /***/ }),
-/* 826 */
+/* 825 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -96280,8 +96205,8 @@ module.exports = atob.atob = atob;
 
 var fs = __webpack_require__(23);
 var path = __webpack_require__(16);
-var define = __webpack_require__(730);
-var utils = __webpack_require__(807);
+var define = __webpack_require__(729);
+var utils = __webpack_require__(806);
 
 /**
  * Expose `mixin()`.
@@ -96424,19 +96349,19 @@ exports.comment = function(node) {
 
 
 /***/ }),
-/* 827 */
+/* 826 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var use = __webpack_require__(799);
+var use = __webpack_require__(798);
 var util = __webpack_require__(29);
-var Cache = __webpack_require__(828);
-var define = __webpack_require__(730);
-var debug = __webpack_require__(801)('snapdragon:parser');
-var Position = __webpack_require__(829);
-var utils = __webpack_require__(807);
+var Cache = __webpack_require__(827);
+var define = __webpack_require__(729);
+var debug = __webpack_require__(800)('snapdragon:parser');
+var Position = __webpack_require__(828);
+var utils = __webpack_require__(806);
 
 /**
  * Create a new `Parser` with the given `input` and `options`.
@@ -96964,7 +96889,7 @@ module.exports = Parser;
 
 
 /***/ }),
-/* 828 */
+/* 827 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -97071,13 +96996,13 @@ MapCache.prototype.del = function mapDelete(key) {
 
 
 /***/ }),
-/* 829 */
+/* 828 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var define = __webpack_require__(730);
+var define = __webpack_require__(729);
 
 /**
  * Store position for a node
@@ -97092,16 +97017,16 @@ module.exports = function Position(start, parser) {
 
 
 /***/ }),
-/* 830 */
+/* 829 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var safe = __webpack_require__(831);
-var define = __webpack_require__(837);
-var extend = __webpack_require__(838);
-var not = __webpack_require__(840);
+var safe = __webpack_require__(830);
+var define = __webpack_require__(836);
+var extend = __webpack_require__(837);
+var not = __webpack_require__(839);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -97254,10 +97179,10 @@ module.exports.makeRe = makeRe;
 
 
 /***/ }),
-/* 831 */
+/* 830 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var parse = __webpack_require__(832);
+var parse = __webpack_require__(831);
 var types = parse.types;
 
 module.exports = function (re, opts) {
@@ -97303,13 +97228,13 @@ function isRegExp (x) {
 
 
 /***/ }),
-/* 832 */
+/* 831 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var util      = __webpack_require__(833);
-var types     = __webpack_require__(834);
-var sets      = __webpack_require__(835);
-var positions = __webpack_require__(836);
+var util      = __webpack_require__(832);
+var types     = __webpack_require__(833);
+var sets      = __webpack_require__(834);
+var positions = __webpack_require__(835);
 
 
 module.exports = function(regexpStr) {
@@ -97591,11 +97516,11 @@ module.exports.types = types;
 
 
 /***/ }),
-/* 833 */
+/* 832 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var types = __webpack_require__(834);
-var sets  = __webpack_require__(835);
+var types = __webpack_require__(833);
+var sets  = __webpack_require__(834);
 
 
 // All of these are private and only used by randexp.
@@ -97708,7 +97633,7 @@ exports.error = function(regexp, msg) {
 
 
 /***/ }),
-/* 834 */
+/* 833 */
 /***/ (function(module, exports) {
 
 module.exports = {
@@ -97724,10 +97649,10 @@ module.exports = {
 
 
 /***/ }),
-/* 835 */
+/* 834 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var types = __webpack_require__(834);
+var types = __webpack_require__(833);
 
 var INTS = function() {
  return [{ type: types.RANGE , from: 48, to: 57 }];
@@ -97812,10 +97737,10 @@ exports.anyChar = function() {
 
 
 /***/ }),
-/* 836 */
+/* 835 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var types = __webpack_require__(834);
+var types = __webpack_require__(833);
 
 exports.wordBoundary = function() {
   return { type: types.POSITION, value: 'b' };
@@ -97835,7 +97760,7 @@ exports.end = function() {
 
 
 /***/ }),
-/* 837 */
+/* 836 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -97848,8 +97773,8 @@ exports.end = function() {
 
 
 
-var isobject = __webpack_require__(748);
-var isDescriptor = __webpack_require__(760);
+var isobject = __webpack_require__(747);
+var isDescriptor = __webpack_require__(759);
 var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty)
   ? Reflect.defineProperty
   : Object.defineProperty;
@@ -97880,14 +97805,14 @@ module.exports = function defineProperty(obj, key, val) {
 
 
 /***/ }),
-/* 838 */
+/* 837 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isExtendable = __webpack_require__(839);
-var assignSymbols = __webpack_require__(749);
+var isExtendable = __webpack_require__(838);
+var assignSymbols = __webpack_require__(748);
 
 module.exports = Object.assign || function(obj/*, objects*/) {
   if (obj === null || typeof obj === 'undefined') {
@@ -97947,7 +97872,7 @@ function isEnum(obj, key) {
 
 
 /***/ }),
-/* 839 */
+/* 838 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -97960,7 +97885,7 @@ function isEnum(obj, key) {
 
 
 
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(746);
 
 module.exports = function isExtendable(val) {
   return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -97968,14 +97893,14 @@ module.exports = function isExtendable(val) {
 
 
 /***/ }),
-/* 840 */
+/* 839 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var extend = __webpack_require__(838);
-var safe = __webpack_require__(831);
+var extend = __webpack_require__(837);
+var safe = __webpack_require__(830);
 
 /**
  * The main export is a function that takes a `pattern` string and an `options` object.
@@ -98047,14 +97972,14 @@ module.exports = toRegex;
 
 
 /***/ }),
-/* 841 */
+/* 840 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var nanomatch = __webpack_require__(842);
-var extglob = __webpack_require__(857);
+var nanomatch = __webpack_require__(841);
+var extglob = __webpack_require__(856);
 
 module.exports = function(snapdragon) {
   var compilers = snapdragon.compiler.compilers;
@@ -98131,7 +98056,7 @@ function escapeExtglobs(compiler) {
 
 
 /***/ }),
-/* 842 */
+/* 841 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -98142,17 +98067,17 @@ function escapeExtglobs(compiler) {
  */
 
 var util = __webpack_require__(29);
-var toRegex = __webpack_require__(729);
-var extend = __webpack_require__(843);
+var toRegex = __webpack_require__(728);
+var extend = __webpack_require__(842);
 
 /**
  * Local dependencies
  */
 
-var compilers = __webpack_require__(845);
-var parsers = __webpack_require__(846);
-var cache = __webpack_require__(849);
-var utils = __webpack_require__(851);
+var compilers = __webpack_require__(844);
+var parsers = __webpack_require__(845);
+var cache = __webpack_require__(848);
+var utils = __webpack_require__(850);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -98976,14 +98901,14 @@ module.exports = nanomatch;
 
 
 /***/ }),
-/* 843 */
+/* 842 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var isExtendable = __webpack_require__(844);
-var assignSymbols = __webpack_require__(749);
+var isExtendable = __webpack_require__(843);
+var assignSymbols = __webpack_require__(748);
 
 module.exports = Object.assign || function(obj/*, objects*/) {
   if (obj === null || typeof obj === 'undefined') {
@@ -99043,7 +98968,7 @@ function isEnum(obj, key) {
 
 
 /***/ }),
-/* 844 */
+/* 843 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -99056,7 +98981,7 @@ function isEnum(obj, key) {
 
 
 
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(746);
 
 module.exports = function isExtendable(val) {
   return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -99064,7 +98989,7 @@ module.exports = function isExtendable(val) {
 
 
 /***/ }),
-/* 845 */
+/* 844 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -99410,15 +99335,15 @@ module.exports = function(nanomatch, options) {
 
 
 /***/ }),
-/* 846 */
+/* 845 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var regexNot = __webpack_require__(740);
-var toRegex = __webpack_require__(729);
-var isOdd = __webpack_require__(847);
+var regexNot = __webpack_require__(739);
+var toRegex = __webpack_require__(728);
+var isOdd = __webpack_require__(846);
 
 /**
  * Characters to use in negation regex (we want to "not" match
@@ -99804,7 +99729,7 @@ module.exports.not = NOT_REGEX;
 
 
 /***/ }),
-/* 847 */
+/* 846 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -99817,7 +99742,7 @@ module.exports.not = NOT_REGEX;
 
 
 
-var isNumber = __webpack_require__(848);
+var isNumber = __webpack_require__(847);
 
 module.exports = function isOdd(i) {
   if (!isNumber(i)) {
@@ -99831,7 +99756,7 @@ module.exports = function isOdd(i) {
 
 
 /***/ }),
-/* 848 */
+/* 847 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -99859,14 +99784,14 @@ module.exports = function isNumber(num) {
 
 
 /***/ }),
-/* 849 */
+/* 848 */
 /***/ (function(module, exports, __webpack_require__) {
 
-module.exports = new (__webpack_require__(850))();
+module.exports = new (__webpack_require__(849))();
 
 
 /***/ }),
-/* 850 */
+/* 849 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -99879,7 +99804,7 @@ module.exports = new (__webpack_require__(850))();
 
 
 
-var MapCache = __webpack_require__(828);
+var MapCache = __webpack_require__(827);
 
 /**
  * Create a new `FragmentCache` with an optional object to use for `caches`.
@@ -100001,7 +99926,7 @@ exports = module.exports = FragmentCache;
 
 
 /***/ }),
-/* 851 */
+/* 850 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -100014,14 +99939,14 @@ var path = __webpack_require__(16);
  * Module dependencies
  */
 
-var isWindows = __webpack_require__(852)();
-var Snapdragon = __webpack_require__(768);
-utils.define = __webpack_require__(853);
-utils.diff = __webpack_require__(854);
-utils.extend = __webpack_require__(843);
-utils.pick = __webpack_require__(855);
-utils.typeOf = __webpack_require__(856);
-utils.unique = __webpack_require__(741);
+var isWindows = __webpack_require__(851)();
+var Snapdragon = __webpack_require__(767);
+utils.define = __webpack_require__(852);
+utils.diff = __webpack_require__(853);
+utils.extend = __webpack_require__(842);
+utils.pick = __webpack_require__(854);
+utils.typeOf = __webpack_require__(855);
+utils.unique = __webpack_require__(740);
 
 /**
  * Returns true if the given value is effectively an empty string
@@ -100387,7 +100312,7 @@ utils.unixify = function(options) {
 
 
 /***/ }),
-/* 852 */
+/* 851 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
@@ -100415,7 +100340,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
 
 
 /***/ }),
-/* 853 */
+/* 852 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -100428,8 +100353,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
 
 
 
-var isobject = __webpack_require__(748);
-var isDescriptor = __webpack_require__(760);
+var isobject = __webpack_require__(747);
+var isDescriptor = __webpack_require__(759);
 var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty)
   ? Reflect.defineProperty
   : Object.defineProperty;
@@ -100460,7 +100385,7 @@ module.exports = function defineProperty(obj, key, val) {
 
 
 /***/ }),
-/* 854 */
+/* 853 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -100514,7 +100439,7 @@ function diffArray(one, two) {
 
 
 /***/ }),
-/* 855 */
+/* 854 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -100527,7 +100452,7 @@ function diffArray(one, two) {
 
 
 
-var isObject = __webpack_require__(748);
+var isObject = __webpack_require__(747);
 
 module.exports = function pick(obj, keys) {
   if (!isObject(obj) && typeof obj !== 'function') {
@@ -100556,7 +100481,7 @@ module.exports = function pick(obj, keys) {
 
 
 /***/ }),
-/* 856 */
+/* 855 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -100691,7 +100616,7 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 857 */
+/* 856 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -100701,18 +100626,18 @@ function isBuffer(val) {
  * Module dependencies
  */
 
-var extend = __webpack_require__(738);
-var unique = __webpack_require__(741);
-var toRegex = __webpack_require__(729);
+var extend = __webpack_require__(737);
+var unique = __webpack_require__(740);
+var toRegex = __webpack_require__(728);
 
 /**
  * Local dependencies
  */
 
-var compilers = __webpack_require__(858);
-var parsers = __webpack_require__(864);
-var Extglob = __webpack_require__(867);
-var utils = __webpack_require__(866);
+var compilers = __webpack_require__(857);
+var parsers = __webpack_require__(863);
+var Extglob = __webpack_require__(866);
+var utils = __webpack_require__(865);
 var MAX_LENGTH = 1024 * 64;
 
 /**
@@ -101029,13 +100954,13 @@ module.exports = extglob;
 
 
 /***/ }),
-/* 858 */
+/* 857 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var brackets = __webpack_require__(859);
+var brackets = __webpack_require__(858);
 
 /**
  * Extglob compilers
@@ -101205,7 +101130,7 @@ module.exports = function(extglob) {
 
 
 /***/ }),
-/* 859 */
+/* 858 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -101215,17 +101140,17 @@ module.exports = function(extglob) {
  * Local dependencies
  */
 
-var compilers = __webpack_require__(860);
-var parsers = __webpack_require__(862);
+var compilers = __webpack_require__(859);
+var parsers = __webpack_require__(861);
 
 /**
  * Module dependencies
  */
 
-var debug = __webpack_require__(801)('expand-brackets');
-var extend = __webpack_require__(738);
-var Snapdragon = __webpack_require__(768);
-var toRegex = __webpack_require__(729);
+var debug = __webpack_require__(800)('expand-brackets');
+var extend = __webpack_require__(737);
+var Snapdragon = __webpack_require__(767);
+var toRegex = __webpack_require__(728);
 
 /**
  * Parses the given POSIX character class `pattern` and returns a
@@ -101423,13 +101348,13 @@ module.exports = brackets;
 
 
 /***/ }),
-/* 860 */
+/* 859 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var posix = __webpack_require__(861);
+var posix = __webpack_require__(860);
 
 module.exports = function(brackets) {
   brackets.compiler
@@ -101517,7 +101442,7 @@ module.exports = function(brackets) {
 
 
 /***/ }),
-/* 861 */
+/* 860 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -101546,14 +101471,14 @@ module.exports = {
 
 
 /***/ }),
-/* 862 */
+/* 861 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var utils = __webpack_require__(863);
-var define = __webpack_require__(730);
+var utils = __webpack_require__(862);
+var define = __webpack_require__(729);
 
 /**
  * Text regex
@@ -101772,14 +101697,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX;
 
 
 /***/ }),
-/* 863 */
+/* 862 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var toRegex = __webpack_require__(729);
-var regexNot = __webpack_require__(740);
+var toRegex = __webpack_require__(728);
+var regexNot = __webpack_require__(739);
 var cached;
 
 /**
@@ -101813,15 +101738,15 @@ exports.createRegex = function(pattern, include) {
 
 
 /***/ }),
-/* 864 */
+/* 863 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var brackets = __webpack_require__(859);
-var define = __webpack_require__(865);
-var utils = __webpack_require__(866);
+var brackets = __webpack_require__(858);
+var define = __webpack_require__(864);
+var utils = __webpack_require__(865);
 
 /**
  * Characters to use in text regex (we want to "not" match
@@ -101976,7 +101901,7 @@ module.exports = parsers;
 
 
 /***/ }),
-/* 865 */
+/* 864 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -101989,7 +101914,7 @@ module.exports = parsers;
 
 
 
-var isDescriptor = __webpack_require__(760);
+var isDescriptor = __webpack_require__(759);
 
 module.exports = function defineProperty(obj, prop, val) {
   if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -102014,14 +101939,14 @@ module.exports = function defineProperty(obj, prop, val) {
 
 
 /***/ }),
-/* 866 */
+/* 865 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var regex = __webpack_require__(740);
-var Cache = __webpack_require__(850);
+var regex = __webpack_require__(739);
+var Cache = __webpack_require__(849);
 
 /**
  * Utils
@@ -102090,7 +102015,7 @@ utils.createRegex = function(str) {
 
 
 /***/ }),
-/* 867 */
+/* 866 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102100,16 +102025,16 @@ utils.createRegex = function(str) {
  * Module dependencies
  */
 
-var Snapdragon = __webpack_require__(768);
-var define = __webpack_require__(865);
-var extend = __webpack_require__(738);
+var Snapdragon = __webpack_require__(767);
+var define = __webpack_require__(864);
+var extend = __webpack_require__(737);
 
 /**
  * Local dependencies
  */
 
-var compilers = __webpack_require__(858);
-var parsers = __webpack_require__(864);
+var compilers = __webpack_require__(857);
+var parsers = __webpack_require__(863);
 
 /**
  * Customize Snapdragon parser and renderer
@@ -102175,16 +102100,16 @@ module.exports = Extglob;
 
 
 /***/ }),
-/* 868 */
+/* 867 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var extglob = __webpack_require__(857);
-var nanomatch = __webpack_require__(842);
-var regexNot = __webpack_require__(740);
-var toRegex = __webpack_require__(830);
+var extglob = __webpack_require__(856);
+var nanomatch = __webpack_require__(841);
+var regexNot = __webpack_require__(739);
+var toRegex = __webpack_require__(829);
 var not;
 
 /**
@@ -102265,14 +102190,14 @@ function textRegex(pattern) {
 
 
 /***/ }),
-/* 869 */
+/* 868 */
 /***/ (function(module, exports, __webpack_require__) {
 
-module.exports = new (__webpack_require__(850))();
+module.exports = new (__webpack_require__(849))();
 
 
 /***/ }),
-/* 870 */
+/* 869 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102285,13 +102210,13 @@ var path = __webpack_require__(16);
  * Module dependencies
  */
 
-var Snapdragon = __webpack_require__(768);
-utils.define = __webpack_require__(837);
-utils.diff = __webpack_require__(854);
-utils.extend = __webpack_require__(838);
-utils.pick = __webpack_require__(855);
-utils.typeOf = __webpack_require__(871);
-utils.unique = __webpack_require__(741);
+var Snapdragon = __webpack_require__(767);
+utils.define = __webpack_require__(836);
+utils.diff = __webpack_require__(853);
+utils.extend = __webpack_require__(837);
+utils.pick = __webpack_require__(854);
+utils.typeOf = __webpack_require__(870);
+utils.unique = __webpack_require__(740);
 
 /**
  * Returns true if the platform is windows, or `path.sep` is `\\`.
@@ -102588,7 +102513,7 @@ utils.unixify = function(options) {
 
 
 /***/ }),
-/* 871 */
+/* 870 */
 /***/ (function(module, exports) {
 
 var toString = Object.prototype.toString;
@@ -102723,7 +102648,7 @@ function isBuffer(val) {
 
 
 /***/ }),
-/* 872 */
+/* 871 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102742,9 +102667,9 @@ var __extends = (this && this.__extends) || (function () {
     };
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
-var readdir = __webpack_require__(873);
-var reader_1 = __webpack_require__(886);
-var fs_stream_1 = __webpack_require__(890);
+var readdir = __webpack_require__(872);
+var reader_1 = __webpack_require__(885);
+var fs_stream_1 = __webpack_require__(889);
 var ReaderAsync = /** @class */ (function (_super) {
     __extends(ReaderAsync, _super);
     function ReaderAsync() {
@@ -102805,15 +102730,15 @@ exports.default = ReaderAsync;
 
 
 /***/ }),
-/* 873 */
+/* 872 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const readdirSync = __webpack_require__(874);
-const readdirAsync = __webpack_require__(882);
-const readdirStream = __webpack_require__(885);
+const readdirSync = __webpack_require__(873);
+const readdirAsync = __webpack_require__(881);
+const readdirStream = __webpack_require__(884);
 
 module.exports = exports = readdirAsyncPath;
 exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath;
@@ -102897,7 +102822,7 @@ function readdirStreamStat (dir, options) {
 
 
 /***/ }),
-/* 874 */
+/* 873 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102905,11 +102830,11 @@ function readdirStreamStat (dir, options) {
 
 module.exports = readdirSync;
 
-const DirectoryReader = __webpack_require__(875);
+const DirectoryReader = __webpack_require__(874);
 
 let syncFacade = {
-  fs: __webpack_require__(880),
-  forEach: __webpack_require__(881),
+  fs: __webpack_require__(879),
+  forEach: __webpack_require__(880),
   sync: true
 };
 
@@ -102938,7 +102863,7 @@ function readdirSync (dir, options, internalOptions) {
 
 
 /***/ }),
-/* 875 */
+/* 874 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -102947,9 +102872,9 @@ function readdirSync (dir, options, internalOptions) {
 const Readable = __webpack_require__(27).Readable;
 const EventEmitter = __webpack_require__(379).EventEmitter;
 const path = __webpack_require__(16);
-const normalizeOptions = __webpack_require__(876);
-const stat = __webpack_require__(878);
-const call = __webpack_require__(879);
+const normalizeOptions = __webpack_require__(875);
+const stat = __webpack_require__(877);
+const call = __webpack_require__(878);
 
 /**
  * Asynchronously reads the contents of a directory and streams the results
@@ -103325,14 +103250,14 @@ module.exports = DirectoryReader;
 
 
 /***/ }),
-/* 876 */
+/* 875 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const path = __webpack_require__(16);
-const globToRegExp = __webpack_require__(877);
+const globToRegExp = __webpack_require__(876);
 
 module.exports = normalizeOptions;
 
@@ -103509,7 +103434,7 @@ function normalizeOptions (options, internalOptions) {
 
 
 /***/ }),
-/* 877 */
+/* 876 */
 /***/ (function(module, exports) {
 
 module.exports = function (glob, opts) {
@@ -103646,13 +103571,13 @@ module.exports = function (glob, opts) {
 
 
 /***/ }),
-/* 878 */
+/* 877 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const call = __webpack_require__(879);
+const call = __webpack_require__(878);
 
 module.exports = stat;
 
@@ -103727,7 +103652,7 @@ function symlinkStat (fs, path, lstats, callback) {
 
 
 /***/ }),
-/* 879 */
+/* 878 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103788,14 +103713,14 @@ function callOnce (fn) {
 
 
 /***/ }),
-/* 880 */
+/* 879 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const fs = __webpack_require__(23);
-const call = __webpack_require__(879);
+const call = __webpack_require__(878);
 
 /**
  * A facade around {@link fs.readdirSync} that allows it to be called
@@ -103859,7 +103784,7 @@ exports.lstat = function (path, callback) {
 
 
 /***/ }),
-/* 881 */
+/* 880 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103888,7 +103813,7 @@ function syncForEach (array, iterator, done) {
 
 
 /***/ }),
-/* 882 */
+/* 881 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103896,12 +103821,12 @@ function syncForEach (array, iterator, done) {
 
 module.exports = readdirAsync;
 
-const maybe = __webpack_require__(883);
-const DirectoryReader = __webpack_require__(875);
+const maybe = __webpack_require__(882);
+const DirectoryReader = __webpack_require__(874);
 
 let asyncFacade = {
   fs: __webpack_require__(23),
-  forEach: __webpack_require__(884),
+  forEach: __webpack_require__(883),
   async: true
 };
 
@@ -103943,7 +103868,7 @@ function readdirAsync (dir, options, callback, internalOptions) {
 
 
 /***/ }),
-/* 883 */
+/* 882 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -103970,7 +103895,7 @@ module.exports = function maybe (cb, promise) {
 
 
 /***/ }),
-/* 884 */
+/* 883 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104006,7 +103931,7 @@ function asyncForEach (array, iterator, done) {
 
 
 /***/ }),
-/* 885 */
+/* 884 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104014,11 +103939,11 @@ function asyncForEach (array, iterator, done) {
 
 module.exports = readdirStream;
 
-const DirectoryReader = __webpack_require__(875);
+const DirectoryReader = __webpack_require__(874);
 
 let streamFacade = {
   fs: __webpack_require__(23),
-  forEach: __webpack_require__(884),
+  forEach: __webpack_require__(883),
   async: true
 };
 
@@ -104038,16 +103963,16 @@ function readdirStream (dir, options, internalOptions) {
 
 
 /***/ }),
-/* 886 */
+/* 885 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
 var path = __webpack_require__(16);
-var deep_1 = __webpack_require__(887);
-var entry_1 = __webpack_require__(889);
-var pathUtil = __webpack_require__(888);
+var deep_1 = __webpack_require__(886);
+var entry_1 = __webpack_require__(888);
+var pathUtil = __webpack_require__(887);
 var Reader = /** @class */ (function () {
     function Reader(options) {
         this.options = options;
@@ -104113,14 +104038,14 @@ exports.default = Reader;
 
 
 /***/ }),
-/* 887 */
+/* 886 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var pathUtils = __webpack_require__(888);
-var patternUtils = __webpack_require__(722);
+var pathUtils = __webpack_require__(887);
+var patternUtils = __webpack_require__(721);
 var DeepFilter = /** @class */ (function () {
     function DeepFilter(options, micromatchOptions) {
         this.options = options;
@@ -104203,7 +104128,7 @@ exports.default = DeepFilter;
 
 
 /***/ }),
-/* 888 */
+/* 887 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104234,14 +104159,14 @@ exports.makeAbsolute = makeAbsolute;
 
 
 /***/ }),
-/* 889 */
+/* 888 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var pathUtils = __webpack_require__(888);
-var patternUtils = __webpack_require__(722);
+var pathUtils = __webpack_require__(887);
+var patternUtils = __webpack_require__(721);
 var EntryFilter = /** @class */ (function () {
     function EntryFilter(options, micromatchOptions) {
         this.options = options;
@@ -104326,7 +104251,7 @@ exports.default = EntryFilter;
 
 
 /***/ }),
-/* 890 */
+/* 889 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104346,8 +104271,8 @@ var __extends = (this && this.__extends) || (function () {
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
 var stream = __webpack_require__(27);
-var fsStat = __webpack_require__(891);
-var fs_1 = __webpack_require__(895);
+var fsStat = __webpack_require__(890);
+var fs_1 = __webpack_require__(894);
 var FileSystemStream = /** @class */ (function (_super) {
     __extends(FileSystemStream, _super);
     function FileSystemStream() {
@@ -104397,14 +104322,14 @@ exports.default = FileSystemStream;
 
 
 /***/ }),
-/* 891 */
+/* 890 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const optionsManager = __webpack_require__(892);
-const statProvider = __webpack_require__(894);
+const optionsManager = __webpack_require__(891);
+const statProvider = __webpack_require__(893);
 /**
  * Asynchronous API.
  */
@@ -104435,13 +104360,13 @@ exports.statSync = statSync;
 
 
 /***/ }),
-/* 892 */
+/* 891 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-const fsAdapter = __webpack_require__(893);
+const fsAdapter = __webpack_require__(892);
 function prepare(opts) {
     const options = Object.assign({
         fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined),
@@ -104454,7 +104379,7 @@ exports.prepare = prepare;
 
 
 /***/ }),
-/* 893 */
+/* 892 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104477,7 +104402,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter;
 
 
 /***/ }),
-/* 894 */
+/* 893 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104529,7 +104454,7 @@ exports.isFollowedSymlink = isFollowedSymlink;
 
 
 /***/ }),
-/* 895 */
+/* 894 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104560,7 +104485,7 @@ exports.default = FileSystem;
 
 
 /***/ }),
-/* 896 */
+/* 895 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104580,9 +104505,9 @@ var __extends = (this && this.__extends) || (function () {
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
 var stream = __webpack_require__(27);
-var readdir = __webpack_require__(873);
-var reader_1 = __webpack_require__(886);
-var fs_stream_1 = __webpack_require__(890);
+var readdir = __webpack_require__(872);
+var reader_1 = __webpack_require__(885);
+var fs_stream_1 = __webpack_require__(889);
 var TransformStream = /** @class */ (function (_super) {
     __extends(TransformStream, _super);
     function TransformStream(reader) {
@@ -104650,7 +104575,7 @@ exports.default = ReaderStream;
 
 
 /***/ }),
-/* 897 */
+/* 896 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104669,9 +104594,9 @@ var __extends = (this && this.__extends) || (function () {
     };
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
-var readdir = __webpack_require__(873);
-var reader_1 = __webpack_require__(886);
-var fs_sync_1 = __webpack_require__(898);
+var readdir = __webpack_require__(872);
+var reader_1 = __webpack_require__(885);
+var fs_sync_1 = __webpack_require__(897);
 var ReaderSync = /** @class */ (function (_super) {
     __extends(ReaderSync, _super);
     function ReaderSync() {
@@ -104731,7 +104656,7 @@ exports.default = ReaderSync;
 
 
 /***/ }),
-/* 898 */
+/* 897 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104750,8 +104675,8 @@ var __extends = (this && this.__extends) || (function () {
     };
 })();
 Object.defineProperty(exports, "__esModule", { value: true });
-var fsStat = __webpack_require__(891);
-var fs_1 = __webpack_require__(895);
+var fsStat = __webpack_require__(890);
+var fs_1 = __webpack_require__(894);
 var FileSystemSync = /** @class */ (function (_super) {
     __extends(FileSystemSync, _super);
     function FileSystemSync() {
@@ -104797,7 +104722,7 @@ exports.default = FileSystemSync;
 
 
 /***/ }),
-/* 899 */
+/* 898 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -104813,13 +104738,13 @@ exports.flatten = flatten;
 
 
 /***/ }),
-/* 900 */
+/* 899 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", { value: true });
-var merge2 = __webpack_require__(589);
+var merge2 = __webpack_require__(588);
 /**
  * Merge multiple streams and propagate their errors into one stream in parallel.
  */
@@ -104834,13 +104759,13 @@ exports.merge = merge;
 
 
 /***/ }),
-/* 901 */
+/* 900 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const path = __webpack_require__(16);
-const pathType = __webpack_require__(902);
+const pathType = __webpack_require__(901);
 
 const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
 
@@ -104906,13 +104831,13 @@ module.exports.sync = (input, opts) => {
 
 
 /***/ }),
-/* 902 */
+/* 901 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const fs = __webpack_require__(23);
-const pify = __webpack_require__(903);
+const pify = __webpack_require__(902);
 
 function type(fn, fn2, fp) {
 	if (typeof fp !== 'string') {
@@ -104955,7 +104880,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink');
 
 
 /***/ }),
-/* 903 */
+/* 902 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105046,17 +104971,17 @@ module.exports = (obj, opts) => {
 
 
 /***/ }),
-/* 904 */
+/* 903 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const fs = __webpack_require__(23);
 const path = __webpack_require__(16);
-const fastGlob = __webpack_require__(718);
-const gitIgnore = __webpack_require__(905);
-const pify = __webpack_require__(906);
-const slash = __webpack_require__(907);
+const fastGlob = __webpack_require__(717);
+const gitIgnore = __webpack_require__(904);
+const pify = __webpack_require__(905);
+const slash = __webpack_require__(906);
 
 const DEFAULT_IGNORE = [
 	'**/node_modules/**',
@@ -105154,7 +105079,7 @@ module.exports.sync = options => {
 
 
 /***/ }),
-/* 905 */
+/* 904 */
 /***/ (function(module, exports) {
 
 // A simple implementation of make-array
@@ -105623,7 +105548,7 @@ module.exports = options => new IgnoreBase(options)
 
 
 /***/ }),
-/* 906 */
+/* 905 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105698,7 +105623,7 @@ module.exports = (input, options) => {
 
 
 /***/ }),
-/* 907 */
+/* 906 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -105716,17 +105641,17 @@ module.exports = input => {
 
 
 /***/ }),
-/* 908 */
+/* 907 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const path = __webpack_require__(16);
 const {constants: fsConstants} = __webpack_require__(23);
-const pEvent = __webpack_require__(909);
-const CpFileError = __webpack_require__(912);
-const fs = __webpack_require__(916);
-const ProgressEmitter = __webpack_require__(919);
+const pEvent = __webpack_require__(908);
+const CpFileError = __webpack_require__(911);
+const fs = __webpack_require__(915);
+const ProgressEmitter = __webpack_require__(918);
 
 const cpFileAsync = async (source, destination, options, progressEmitter) => {
 	let readError;
@@ -105840,12 +105765,12 @@ module.exports.sync = (source, destination, options) => {
 
 
 /***/ }),
-/* 909 */
+/* 908 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const pTimeout = __webpack_require__(910);
+const pTimeout = __webpack_require__(909);
 
 const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator';
 
@@ -106136,12 +106061,12 @@ module.exports.iterator = (emitter, event, options) => {
 
 
 /***/ }),
-/* 910 */
+/* 909 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const pFinally = __webpack_require__(911);
+const pFinally = __webpack_require__(910);
 
 class TimeoutError extends Error {
 	constructor(message) {
@@ -106187,7 +106112,7 @@ module.exports.TimeoutError = TimeoutError;
 
 
 /***/ }),
-/* 911 */
+/* 910 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -106209,12 +106134,12 @@ module.exports = (promise, onFinally) => {
 
 
 /***/ }),
-/* 912 */
+/* 911 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const NestedError = __webpack_require__(913);
+const NestedError = __webpack_require__(912);
 
 class CpFileError extends NestedError {
 	constructor(message, nested) {
@@ -106228,10 +106153,10 @@ module.exports = CpFileError;
 
 
 /***/ }),
-/* 913 */
+/* 912 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var inherits = __webpack_require__(914);
+var inherits = __webpack_require__(913);
 
 var NestedError = function (message, nested) {
     this.nested = nested;
@@ -106282,7 +106207,7 @@ module.exports = NestedError;
 
 
 /***/ }),
-/* 914 */
+/* 913 */
 /***/ (function(module, exports, __webpack_require__) {
 
 try {
@@ -106290,12 +106215,12 @@ try {
   if (typeof util.inherits !== 'function') throw '';
   module.exports = util.inherits;
 } catch (e) {
-  module.exports = __webpack_require__(915);
+  module.exports = __webpack_require__(914);
 }
 
 
 /***/ }),
-/* 915 */
+/* 914 */
 /***/ (function(module, exports) {
 
 if (typeof Object.create === 'function') {
@@ -106324,16 +106249,16 @@ if (typeof Object.create === 'function') {
 
 
 /***/ }),
-/* 916 */
+/* 915 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 const {promisify} = __webpack_require__(29);
 const fs = __webpack_require__(22);
-const makeDir = __webpack_require__(917);
-const pEvent = __webpack_require__(909);
-const CpFileError = __webpack_require__(912);
+const makeDir = __webpack_require__(916);
+const pEvent = __webpack_require__(908);
+const CpFileError = __webpack_require__(911);
 
 const stat = promisify(fs.stat);
 const lstat = promisify(fs.lstat);
@@ -106430,7 +106355,7 @@ exports.copyFileSync = (source, destination, flags) => {
 
 
 /***/ }),
-/* 917 */
+/* 916 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -106438,7 +106363,7 @@ exports.copyFileSync = (source, destination, flags) => {
 const fs = __webpack_require__(23);
 const path = __webpack_require__(16);
 const {promisify} = __webpack_require__(29);
-const semver = __webpack_require__(918);
+const semver = __webpack_require__(917);
 
 const defaults = {
 	mode: 0o777 & (~process.umask()),
@@ -106587,7 +106512,7 @@ module.exports.sync = (input, options) => {
 
 
 /***/ }),
-/* 918 */
+/* 917 */
 /***/ (function(module, exports) {
 
 exports = module.exports = SemVer
@@ -108189,7 +108114,7 @@ function coerce (version, options) {
 
 
 /***/ }),
-/* 919 */
+/* 918 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -108230,7 +108155,7 @@ module.exports = ProgressEmitter;
 
 
 /***/ }),
-/* 920 */
+/* 919 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -108276,12 +108201,12 @@ exports.default = module.exports;
 
 
 /***/ }),
-/* 921 */
+/* 920 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
-const NestedError = __webpack_require__(922);
+const NestedError = __webpack_require__(921);
 
 class CpyError extends NestedError {
 	constructor(message, nested) {
@@ -108295,7 +108220,7 @@ module.exports = CpyError;
 
 
 /***/ }),
-/* 922 */
+/* 921 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var inherits = __webpack_require__(29).inherits;
@@ -108351,7 +108276,7 @@ module.exports = NestedError;
 
 
 /***/ }),
-/* 923 */
+/* 922 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
diff --git a/yarn.lock b/yarn.lock
index 20e33fdefc996..11abd95498c8d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -61,7 +61,7 @@
     semver "^5.4.1"
     source-map "^0.5.0"
 
-"@babel/core@^7.0.0", "@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.4.3", "@babel/core@^7.9.0":
+"@babel/core@^7.0.0", "@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.4.3", "@babel/core@^7.7.5", "@babel/core@^7.9.0":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e"
   integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==
@@ -83,7 +83,7 @@
     semver "^5.4.1"
     source-map "^0.5.0"
 
-"@babel/generator@^7.0.0", "@babel/generator@^7.4.0", "@babel/generator@^7.5.5", "@babel/generator@^7.9.0":
+"@babel/generator@^7.0.0", "@babel/generator@^7.5.5", "@babel/generator@^7.9.0":
   version "7.9.4"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce"
   integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==
@@ -93,6 +93,16 @@
     lodash "^4.17.13"
     source-map "^0.5.0"
 
+"@babel/generator@^7.9.5":
+  version "7.9.5"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9"
+  integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==
+  dependencies:
+    "@babel/types" "^7.9.5"
+    jsesc "^2.5.1"
+    lodash "^4.17.13"
+    source-map "^0.5.0"
+
 "@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
@@ -183,6 +193,15 @@
     "@babel/template" "^7.8.3"
     "@babel/types" "^7.8.3"
 
+"@babel/helper-function-name@^7.9.5":
+  version "7.9.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c"
+  integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.9.5"
+
 "@babel/helper-get-function-arity@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
@@ -284,6 +303,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed"
   integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==
 
+"@babel/helper-validator-identifier@^7.9.5":
+  version "7.9.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80"
+  integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==
+
 "@babel/helper-wrap-function@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
@@ -312,7 +336,7 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.2.0", "@babel/parser@^7.4.3", "@babel/parser@^7.5.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0", "@babel/parser@^7.9.3":
+"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.2.0", "@babel/parser@^7.5.5", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0", "@babel/parser@^7.9.3":
   version "7.9.4"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8"
   integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==
@@ -1101,7 +1125,7 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
-"@babel/template@^7.0.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
+"@babel/template@^7.0.0", "@babel/template@^7.4.4", "@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
   version "7.8.6"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
   integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==
@@ -1110,7 +1134,7 @@
     "@babel/parser" "^7.8.6"
     "@babel/types" "^7.8.6"
 
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.5", "@babel/traverse@^7.5.5", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0":
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.4.5", "@babel/traverse@^7.5.5", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892"
   integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==
@@ -1125,6 +1149,21 @@
     globals "^11.1.0"
     lodash "^4.17.13"
 
+"@babel/traverse@^7.7.4":
+  version "7.9.5"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2"
+  integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.9.5"
+    "@babel/helper-function-name" "^7.9.5"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/parser" "^7.9.0"
+    "@babel/types" "^7.9.5"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.13"
+
 "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5"
@@ -1134,6 +1173,15 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.9.5":
+  version "7.9.5"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444"
+  integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.9.5"
+    lodash "^4.17.13"
+    to-fast-properties "^2.0.0"
+
 "@cnakazawa/watch@^1.0.3":
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
@@ -1542,6 +1590,21 @@
   resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
   integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
 
+"@istanbuljs/load-nyc-config@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b"
+  integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==
+  dependencies:
+    camelcase "^5.3.1"
+    find-up "^4.1.0"
+    js-yaml "^3.13.1"
+    resolve-from "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
+  integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
+
 "@jest/console@^24.7.1":
   version "24.7.1"
   resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545"
@@ -6109,12 +6172,12 @@ append-buffer@^1.0.2:
   dependencies:
     buffer-equal "^1.0.0"
 
-append-transform@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab"
-  integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==
+append-transform@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12"
+  integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==
   dependencies:
-    default-require-extensions "^2.0.0"
+    default-require-extensions "^3.0.0"
 
 aproba@^1.0.3, aproba@^1.1.1:
   version "1.2.0"
@@ -6867,15 +6930,16 @@ babel-plugin-istanbul@^5.1.0:
     istanbul-lib-instrument "^3.0.0"
     test-exclude "^5.0.0"
 
-babel-plugin-istanbul@^5.2.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854"
-  integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==
+babel-plugin-istanbul@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
+  integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==
   dependencies:
     "@babel/helper-plugin-utils" "^7.0.0"
-    find-up "^3.0.0"
-    istanbul-lib-instrument "^3.3.0"
-    test-exclude "^5.2.3"
+    "@istanbuljs/load-nyc-config" "^1.0.0"
+    "@istanbuljs/schema" "^0.1.2"
+    istanbul-lib-instrument "^4.0.0"
+    test-exclude "^6.0.0"
 
 babel-plugin-jest-hoist@^24.9.0:
   version "24.9.0"
@@ -8129,15 +8193,15 @@ cachedir@2.3.0:
   resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8"
   integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==
 
-caching-transform@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-3.0.2.tgz#601d46b91eca87687a281e71cef99791b0efca70"
-  integrity sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==
+caching-transform@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f"
+  integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==
   dependencies:
-    hasha "^3.0.0"
-    make-dir "^2.0.0"
-    package-hash "^3.0.0"
-    write-file-atomic "^2.4.2"
+    hasha "^5.0.0"
+    make-dir "^3.0.0"
+    package-hash "^4.0.0"
+    write-file-atomic "^3.0.0"
 
 call-me-maybe@^1.0.1:
   version "1.0.1"
@@ -9564,7 +9628,7 @@ convert-source-map@^0.3.3:
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
   integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
 
-convert-source-map@^1.5.1, convert-source-map@^1.6.0:
+convert-source-map@^1.5.1:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
   integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
@@ -9768,17 +9832,6 @@ cosmiconfig@^5.2.0, cosmiconfig@^5.2.1:
     js-yaml "^3.13.1"
     parse-json "^4.0.0"
 
-cp-file@^6.2.0:
-  version "6.2.0"
-  resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.2.0.tgz#40d5ea4a1def2a9acdd07ba5c0b0246ef73dc10d"
-  integrity sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==
-  dependencies:
-    graceful-fs "^4.1.2"
-    make-dir "^2.0.0"
-    nested-error-stacks "^2.0.0"
-    pify "^4.0.1"
-    safe-buffer "^5.0.1"
-
 cp-file@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd"
@@ -9948,7 +10001,7 @@ cross-spawn@^3.0.0:
     lru-cache "^4.0.1"
     which "^1.2.9"
 
-cross-spawn@^4, cross-spawn@^4.0.2:
+cross-spawn@^4.0.2:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
   integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=
@@ -10847,12 +10900,12 @@ default-gateway@^4.2.0:
     execa "^1.0.0"
     ip-regex "^2.1.0"
 
-default-require-extensions@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7"
-  integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=
+default-require-extensions@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96"
+  integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==
   dependencies:
-    strip-bom "^3.0.0"
+    strip-bom "^4.0.0"
 
 default-resolution@^2.0.0:
   version "2.0.0"
@@ -13842,13 +13895,13 @@ foreachasync@^3.0.0:
   resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6"
   integrity sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=
 
-foreground-child@^1.5.6:
-  version "1.5.6"
-  resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9"
-  integrity sha1-T9ca0t/elnibmApcCilZN8svXOk=
+foreground-child@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53"
+  integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==
   dependencies:
-    cross-spawn "^4"
-    signal-exit "^3.0.0"
+    cross-spawn "^7.0.0"
+    signal-exit "^3.0.2"
 
 forever-agent@~0.6.1:
   version "0.6.1"
@@ -13954,6 +14007,11 @@ from2@^2.1.0, from2@^2.1.1, from2@^2.3.0:
     inherits "^2.0.1"
     readable-stream "^2.0.0"
 
+fromentries@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.2.0.tgz#e6aa06f240d6267f913cea422075ef88b63e7897"
+  integrity sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==
+
 front-matter@2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb"
@@ -15636,12 +15694,13 @@ hash.js@^1.0.0, hash.js@^1.0.3:
     inherits "^2.0.3"
     minimalistic-assert "^1.0.0"
 
-hasha@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/hasha/-/hasha-3.0.0.tgz#52a32fab8569d41ca69a61ff1a214f8eb7c8bd39"
-  integrity sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=
+hasha@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.0.tgz#33094d1f69c40a4a6ac7be53d5fe3ff95a269e0c"
+  integrity sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==
   dependencies:
-    is-stream "^1.0.1"
+    is-stream "^2.0.0"
+    type-fest "^0.8.0"
 
 hast-util-from-parse5@^5.0.0:
   version "5.0.0"
@@ -15845,6 +15904,11 @@ html-entities@^1.2.0, html-entities@^1.2.1:
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
   integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
 
+html-escaper@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+  integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
 html-loader@^0.5.5:
   version "0.5.5"
   resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-0.5.5.tgz#6356dbeb0c49756d8ebd5ca327f16ff06ab5faea"
@@ -17320,7 +17384,7 @@ is-symbol@^1.0.2:
   dependencies:
     has-symbols "^1.0.0"
 
-is-typedarray@~1.0.0:
+is-typedarray@^1.0.0, is-typedarray@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
@@ -17482,17 +17546,17 @@ istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3:
   resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#0b891e5ad42312c2b9488554f603795f9a2211ba"
   integrity sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==
 
-istanbul-lib-coverage@^2.0.5:
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
-  integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
+  integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
 
-istanbul-lib-hook@^2.0.7:
-  version "2.0.7"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133"
-  integrity sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==
+istanbul-lib-hook@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6"
+  integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==
   dependencies:
-    append-transform "^1.0.0"
+    append-transform "^2.0.0"
 
 istanbul-lib-instrument@^1.7.3:
   version "1.10.2"
@@ -17520,18 +17584,31 @@ istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1:
     istanbul-lib-coverage "^2.0.3"
     semver "^5.5.0"
 
-istanbul-lib-instrument@^3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630"
-  integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==
+istanbul-lib-instrument@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6"
+  integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==
+  dependencies:
+    "@babel/core" "^7.7.5"
+    "@babel/parser" "^7.7.5"
+    "@babel/template" "^7.7.4"
+    "@babel/traverse" "^7.7.4"
+    "@istanbuljs/schema" "^0.1.2"
+    istanbul-lib-coverage "^3.0.0"
+    semver "^6.3.0"
+
+istanbul-lib-processinfo@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c"
+  integrity sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==
   dependencies:
-    "@babel/generator" "^7.4.0"
-    "@babel/parser" "^7.4.3"
-    "@babel/template" "^7.4.0"
-    "@babel/traverse" "^7.4.3"
-    "@babel/types" "^7.4.0"
-    istanbul-lib-coverage "^2.0.5"
-    semver "^6.0.0"
+    archy "^1.0.0"
+    cross-spawn "^7.0.0"
+    istanbul-lib-coverage "^3.0.0-alpha.1"
+    make-dir "^3.0.0"
+    p-map "^3.0.0"
+    rimraf "^3.0.0"
+    uuid "^3.3.3"
 
 istanbul-lib-report@^2.0.4:
   version "2.0.4"
@@ -17542,14 +17619,14 @@ istanbul-lib-report@^2.0.4:
     make-dir "^1.3.0"
     supports-color "^6.0.0"
 
-istanbul-lib-report@^2.0.8:
-  version "2.0.8"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33"
-  integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==
+istanbul-lib-report@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
+  integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==
   dependencies:
-    istanbul-lib-coverage "^2.0.5"
-    make-dir "^2.1.0"
-    supports-color "^6.1.0"
+    istanbul-lib-coverage "^3.0.0"
+    make-dir "^3.0.0"
+    supports-color "^7.1.0"
 
 istanbul-lib-source-maps@^3.0.1:
   version "3.0.2"
@@ -17562,24 +17639,30 @@ istanbul-lib-source-maps@^3.0.1:
     rimraf "^2.6.2"
     source-map "^0.6.1"
 
-istanbul-lib-source-maps@^3.0.6:
-  version "3.0.6"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8"
-  integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==
+istanbul-lib-source-maps@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9"
+  integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==
   dependencies:
     debug "^4.1.1"
-    istanbul-lib-coverage "^2.0.5"
-    make-dir "^2.1.0"
-    rimraf "^2.6.3"
+    istanbul-lib-coverage "^3.0.0"
     source-map "^0.6.1"
 
-istanbul-reports@^2.2.4, istanbul-reports@^2.2.6:
+istanbul-reports@^2.2.6:
   version "2.2.6"
   resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af"
   integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==
   dependencies:
     handlebars "^4.1.2"
 
+istanbul-reports@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b"
+  integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==
+  dependencies:
+    html-escaper "^2.0.0"
+    istanbul-lib-report "^3.0.0"
+
 istanbul@^0.4.0:
   version "0.4.5"
   resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b"
@@ -20121,13 +20204,6 @@ merge-source-map@1.0.4:
   dependencies:
     source-map "^0.5.6"
 
-merge-source-map@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646"
-  integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==
-  dependencies:
-    source-map "^0.6.1"
-
 merge-stream@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
@@ -21224,6 +21300,13 @@ node-notifier@^5.4.2:
     shellwords "^0.1.1"
     which "^1.3.0"
 
+node-preload@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301"
+  integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==
+  dependencies:
+    process-on-spawn "^1.0.0"
+
 node-releases@^1.1.25, node-releases@^1.1.46:
   version "1.1.47"
   resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4"
@@ -21490,36 +21573,37 @@ nwsapi@^2.2.0:
   resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
   integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
 
-nyc@^14.1.1:
-  version "14.1.1"
-  resolved "https://registry.yarnpkg.com/nyc/-/nyc-14.1.1.tgz#151d64a6a9f9f5908a1b73233931e4a0a3075eeb"
-  integrity sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==
+nyc@^15.0.1:
+  version "15.0.1"
+  resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.0.1.tgz#bd4d5c2b17f2ec04370365a5ca1fc0ed26f9f93d"
+  integrity sha512-n0MBXYBYRqa67IVt62qW1r/d9UH/Qtr7SF1w/nQLJ9KxvWF6b2xCHImRAixHN9tnMMYHC2P14uo6KddNGwMgGg==
   dependencies:
-    archy "^1.0.0"
-    caching-transform "^3.0.2"
-    convert-source-map "^1.6.0"
-    cp-file "^6.2.0"
-    find-cache-dir "^2.1.0"
-    find-up "^3.0.0"
-    foreground-child "^1.5.6"
-    glob "^7.1.3"
-    istanbul-lib-coverage "^2.0.5"
-    istanbul-lib-hook "^2.0.7"
-    istanbul-lib-instrument "^3.3.0"
-    istanbul-lib-report "^2.0.8"
-    istanbul-lib-source-maps "^3.0.6"
-    istanbul-reports "^2.2.4"
-    js-yaml "^3.13.1"
-    make-dir "^2.1.0"
-    merge-source-map "^1.1.0"
-    resolve-from "^4.0.0"
-    rimraf "^2.6.3"
+    "@istanbuljs/load-nyc-config" "^1.0.0"
+    "@istanbuljs/schema" "^0.1.2"
+    caching-transform "^4.0.0"
+    convert-source-map "^1.7.0"
+    decamelize "^1.2.0"
+    find-cache-dir "^3.2.0"
+    find-up "^4.1.0"
+    foreground-child "^2.0.0"
+    glob "^7.1.6"
+    istanbul-lib-coverage "^3.0.0"
+    istanbul-lib-hook "^3.0.0"
+    istanbul-lib-instrument "^4.0.0"
+    istanbul-lib-processinfo "^2.0.2"
+    istanbul-lib-report "^3.0.0"
+    istanbul-lib-source-maps "^4.0.0"
+    istanbul-reports "^3.0.2"
+    make-dir "^3.0.0"
+    node-preload "^0.2.1"
+    p-map "^3.0.0"
+    process-on-spawn "^1.0.0"
+    resolve-from "^5.0.0"
+    rimraf "^3.0.0"
     signal-exit "^3.0.2"
-    spawn-wrap "^1.4.2"
-    test-exclude "^5.2.3"
-    uuid "^3.3.2"
-    yargs "^13.2.2"
-    yargs-parser "^13.0.0"
+    spawn-wrap "^2.0.0"
+    test-exclude "^6.0.0"
+    yargs "^15.0.2"
 
 oauth-sign@~0.8.1, oauth-sign@~0.8.2:
   version "0.8.2"
@@ -21958,7 +22042,7 @@ os-browserify@^0.3.0:
   resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
   integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
 
-os-homedir@^1.0.0, os-homedir@^1.0.1:
+os-homedir@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
   integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
@@ -22200,13 +22284,13 @@ p-try@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
 
-package-hash@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-3.0.0.tgz#50183f2d36c9e3e528ea0a8605dff57ce976f88e"
-  integrity sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==
+package-hash@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506"
+  integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==
   dependencies:
     graceful-fs "^4.1.15"
-    hasha "^3.0.0"
+    hasha "^5.0.0"
     lodash.flattendeep "^4.4.0"
     release-zalgo "^1.0.0"
 
@@ -23202,6 +23286,13 @@ process-nextick-args@~2.0.0:
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
   integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
 
+process-on-spawn@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93"
+  integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==
+  dependencies:
+    fromentries "^1.2.0"
+
 process@^0.11.10:
   version "0.11.10"
   resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -27207,17 +27298,17 @@ spawn-sync@^1.0.15:
     concat-stream "^1.4.7"
     os-shim "^0.1.2"
 
-spawn-wrap@^1.4.2:
-  version "1.4.2"
-  resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c"
-  integrity sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==
+spawn-wrap@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e"
+  integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==
   dependencies:
-    foreground-child "^1.5.6"
-    mkdirp "^0.5.0"
-    os-homedir "^1.0.1"
-    rimraf "^2.6.2"
+    foreground-child "^2.0.0"
+    is-windows "^1.0.2"
+    make-dir "^3.0.0"
+    rimraf "^3.0.0"
     signal-exit "^3.0.2"
-    which "^1.3.0"
+    which "^2.0.1"
 
 spdx-compare@^0.1.2:
   version "0.1.2"
@@ -28536,7 +28627,7 @@ terser@^4.4.3:
     source-map "~0.6.1"
     source-map-support "~0.5.12"
 
-test-exclude@^5.0.0, test-exclude@^5.2.3:
+test-exclude@^5.0.0:
   version "5.2.3"
   resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0"
   integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==
@@ -28546,6 +28637,15 @@ test-exclude@^5.0.0, test-exclude@^5.2.3:
     read-pkg-up "^4.0.0"
     require-main-filename "^2.0.0"
 
+test-exclude@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+  integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
+  dependencies:
+    "@istanbuljs/schema" "^0.1.2"
+    glob "^7.1.4"
+    minimatch "^3.0.4"
+
 text-hex@1.0.x:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
@@ -29688,7 +29788,7 @@ type-fest@^0.6.0:
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
   integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
 
-type-fest@^0.8.1:
+type-fest@^0.8.0, type-fest@^0.8.1:
   version "0.8.1"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
   integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
@@ -29726,6 +29826,13 @@ typed-styles@^0.0.7:
   resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
   integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==
 
+typedarray-to-buffer@^3.1.5:
+  version "3.1.5"
+  resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+  integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+  dependencies:
+    is-typedarray "^1.0.0"
+
 typedarray@^0.0.6, typedarray@~0.0.5:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -30453,6 +30560,11 @@ uuid@^3.0.0:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
   integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==
 
+uuid@^3.3.3:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+  integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
 v8-compile-cache@2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
@@ -31713,6 +31825,16 @@ write-file-atomic@^2.4.2:
     imurmurhash "^0.1.4"
     signal-exit "^3.0.2"
 
+write-file-atomic@^3.0.0:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+  integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
+  dependencies:
+    imurmurhash "^0.1.4"
+    is-typedarray "^1.0.0"
+    signal-exit "^3.0.2"
+    typedarray-to-buffer "^3.1.5"
+
 write-json-file@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a"
@@ -31954,7 +32076,7 @@ yallist@^4.0.0:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
   integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 
-yargs-parser@13.1.2, yargs-parser@^13.0.0, yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2:
+yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2:
   version "13.1.2"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
   integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
@@ -32121,7 +32243,7 @@ yargs@^13.2.2, yargs@^13.3.0:
     y18n "^4.0.0"
     yargs-parser "^13.1.1"
 
-yargs@^15.3.1:
+yargs@^15.0.2, yargs@^15.3.1:
   version "15.3.1"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b"
   integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==

From 97d1685c3dea682f80fd1a907bbc1d6f3702ea85 Mon Sep 17 00:00:00 2001
From: Joe Portner <5295965+jportner@users.noreply.github.com>
Date: Thu, 9 Apr 2020 23:18:18 -0400
Subject: [PATCH 44/78] Sharing saved-objects phase 1 (#54605)

Co-authored-by: kobelb <brandon.kobel@elastic.co>
---
 docs/api/saved-objects/bulk_create.asciidoc   |    2 +-
 .../kibana-plugin-core-public.savedobject.md  |    1 +
 ...ugin-core-public.savedobject.namespaces.md |   13 +
 ...in-core-server.isavedobjecttyperegistry.md |    2 +-
 .../core/server/kibana-plugin-core-server.md  |    3 +
 .../kibana-plugin-core-server.savedobject.md  |    1 +
 ...ugin-core-server.savedobject.namespaces.md |   13 +
 ...rver.savedobjectsaddtonamespacesoptions.md |   20 +
 ...edobjectsaddtonamespacesoptions.refresh.md |   13 +
 ...edobjectsaddtonamespacesoptions.version.md |   13 +
 ...rver.savedobjectsclient.addtonamespaces.md |   27 +
 ...savedobjectsclient.deletefromnamespaces.md |   27 +
 ...a-plugin-core-server.savedobjectsclient.md |    2 +
 ...savedobjectsdeletefromnamespacesoptions.md |   19 +
 ...ectsdeletefromnamespacesoptions.refresh.md |   13 +
 ...objectserrorhelpers.createconflicterror.md |   23 +
 ...pers.decorateescannotexecutescripterror.md |   23 +
 ...rorhelpers.isescannotexecutescripterror.md |   22 +
 ...in-core-server.savedobjectserrorhelpers.md |    3 +
 ...n-core-server.savedobjectsnamespacetype.md |   15 +
 ....savedobjectsrepository.addtonamespaces.md |   27 +
 ...dobjectsrepository.deletefromnamespaces.md |   27 +
 ...ugin-core-server.savedobjectsrepository.md |    2 +
 ...r.savedobjectsservicesetup.registertype.md |    2 +-
 ...ana-plugin-core-server.savedobjectstype.md |    3 +-
 ...rver.savedobjectstype.namespaceagnostic.md |    9 +-
 ...e-server.savedobjectstype.namespacetype.md |   13 +
 ...avedobjecttyperegistry.ismultinamespace.md |   24 +
 ...dobjecttyperegistry.isnamespaceagnostic.md |    2 +-
 ...vedobjecttyperegistry.issinglenamespace.md |   24 +
 ...gin-core-server.savedobjecttyperegistry.md |    4 +-
 src/core/public/public.api.md                 |    1 +
 src/core/server/index.ts                      |    3 +
 .../__snapshots__/utils.test.ts.snap          |   48 +-
 src/core/server/saved_objects/index.ts        |    1 +
 .../build_active_mappings.test.ts.snap        |    8 +
 .../migrations/core/build_active_mappings.ts  |    3 +
 .../migrations/core/index_migrator.test.ts    |    4 +
 .../kibana_migrator.test.ts.snap              |    4 +
 .../routes/integration_tests/import.test.ts   |    2 +-
 .../saved_objects_service.test.ts             |    4 +-
 .../saved_objects/saved_objects_service.ts    |    2 +-
 .../saved_objects_type_registry.mock.ts       |    6 +
 .../saved_objects_type_registry.test.ts       |   98 +-
 .../saved_objects_type_registry.ts            |   37 +-
 .../saved_objects/schema/schema.test.ts       |   98 +-
 .../server/saved_objects/schema/schema.ts     |   33 +-
 .../serialization/serializer.test.ts          | 1710 +++---
 .../saved_objects/serialization/serializer.ts |   15 +-
 .../saved_objects/serialization/types.ts      |    2 +
 .../lib/__snapshots__/repository.test.js.snap |    5 -
 .../service/lib/decorate_es_error.test.ts     |   32 +
 .../service/lib/decorate_es_error.ts          |   10 +-
 .../saved_objects/service/lib/errors.test.ts  |  172 +-
 .../saved_objects/service/lib/errors.ts       |   16 +
 .../service/lib/included_fields.test.ts       |   26 +-
 .../service/lib/included_fields.ts            |    1 +
 .../service/lib/repository.mock.ts            |    2 +
 .../service/lib/repository.test.js            | 4970 +++++++++--------
 .../saved_objects/service/lib/repository.ts   |  769 ++-
 .../lib/search_dsl/query_params.test.ts       | 1460 +----
 .../service/lib/search_dsl/query_params.ts    |   14 +-
 .../service/saved_objects_client.mock.ts      |    2 +
 .../service/saved_objects_client.test.js      |   34 +
 .../service/saved_objects_client.ts           |   54 +
 src/core/server/saved_objects/types.ts        |   24 +-
 src/core/server/saved_objects/utils.test.ts   |   63 +-
 src/core/server/saved_objects/utils.ts        |   11 +-
 src/core/server/server.api.md                 |   37 +-
 src/core/types/saved_objects.ts               |    2 +
 .../apis/saved_objects/bulk_create.js         |    4 +-
 .../apis/saved_objects/bulk_get.js            |   13 +-
 .../apis/saved_objects/export.js              |    3 +-
 ...ypted_saved_objects_client_wrapper.test.ts |  308 +-
 .../encrypted_saved_objects_client_wrapper.ts |   42 +-
 .../server/saved_objects/index.ts             |    3 +-
 .../server/audit/audit_logger.test.ts         |   36 +-
 .../security/server/audit/audit_logger.ts     |   17 +-
 .../check_privileges.test.ts.snap             |   27 -
 .../authorization/check_privileges.test.ts    | 1216 ++--
 .../server/authorization/check_privileges.ts  |   95 +-
 .../check_privileges_dynamically.ts           |    4 +-
 .../check_saved_objects_privileges.test.ts    |  132 +-
 .../check_saved_objects_privileges.ts         |   34 +-
 .../disable_ui_capabilities.test.ts           |   47 +-
 .../authorization/disable_ui_capabilities.ts  |    8 +-
 x-pack/plugins/security/server/plugin.ts      |    1 +
 .../security/server/saved_objects/index.ts    |   10 +-
 ...ecure_saved_objects_client_wrapper.test.ts | 1448 +++--
 .../secure_saved_objects_client_wrapper.ts    |  212 +-
 .../edit_space/delete_spaces_button.tsx       |   11 +-
 .../spaces_grid/spaces_grid_page.tsx          |   11 +-
 .../lib/copy_to_spaces/copy_to_spaces.test.ts |    6 +
 .../resolve_copy_conflicts.test.ts            |    6 +
 .../lib/spaces_client/spaces_client.test.ts   |   24 +-
 .../server/lib/spaces_client/spaces_client.ts |   14 +-
 .../server/routes/api/external/delete.test.ts |   30 +-
 .../server/routes/api/external/delete.ts      |   10 +-
 .../server/routes/api/external/index.ts       |    4 +
 .../routes/api/external/share_add_spaces.ts   |   62 +
 .../api/external/share_remove_spaces.ts       |   62 +
 .../spaces_saved_objects_client.test.ts.snap  |   29 -
 .../spaces_saved_objects_client.test.ts       |  314 +-
 .../spaces_saved_objects_client.ts            |   46 +
 .../plugins/uptime/server/rest_api/types.ts   |   15 +-
 .../apis/spaces/saved_objects.ts              |    2 +-
 .../common/config.ts                          |    2 +
 .../saved_objects/spaces/data.json            |  103 +-
 .../saved_objects/spaces/mappings.json        |   78 +-
 .../fixtures/hidden_type_plugin/index.js      |    2 +
 .../fixtures/hidden_type_plugin/mappings.json |    2 +-
 .../fixtures/isolated_type_plugin/index.js    |   26 +
 .../isolated_type_plugin/mappings.json        |   31 +
 .../isolated_type_plugin/package.json         |    7 +
 .../mappings.json                             |    2 +-
 .../fixtures/shared_type_plugin/index.js      |   27 +
 .../fixtures/shared_type_plugin/mappings.json |   15 +
 .../fixtures/shared_type_plugin/package.json  |    7 +
 .../common/lib/saved_object_test_cases.ts     |   40 +
 .../common/lib/saved_object_test_utils.ts     |  302 +
 .../common/lib/space_test_utils.ts            |   24 -
 .../common/lib/types.ts                       |   27 +-
 .../common/suites/bulk_create.ts              |  293 +-
 .../common/suites/bulk_get.ts                 |  257 +-
 .../common/suites/bulk_update.ts              |  291 +-
 .../common/suites/create.ts                   |  259 +-
 .../common/suites/delete.ts                   |  190 +-
 .../common/suites/export.ts                   |  291 +-
 .../common/suites/find.ts                     |  401 +-
 .../common/suites/get.ts                      |  226 +-
 .../common/suites/import.ts                   |  285 +-
 .../common/suites/resolve_import_errors.ts    |  312 +-
 .../common/suites/update.ts                   |  246 +-
 .../security_and_spaces/apis/bulk_create.ts   |  278 +-
 .../security_and_spaces/apis/bulk_get.ts      |  260 +-
 .../security_and_spaces/apis/bulk_update.ts   |  347 +-
 .../security_and_spaces/apis/create.ts        |  313 +-
 .../security_and_spaces/apis/delete.ts        |  337 +-
 .../security_and_spaces/apis/export.ts        |  314 +-
 .../security_and_spaces/apis/find.ts          |  766 +--
 .../security_and_spaces/apis/get.ts           |  339 +-
 .../security_and_spaces/apis/import.ts        |  301 +-
 .../security_and_spaces/apis/index.ts         |    2 +-
 .../apis/resolve_import_errors.ts             |  325 +-
 .../security_and_spaces/apis/update.ts        |  338 +-
 .../security_only/apis/bulk_create.ts         |  232 +-
 .../security_only/apis/bulk_get.ts            |  226 +-
 .../security_only/apis/bulk_update.ts         |  323 +-
 .../security_only/apis/create.ts              |  275 +-
 .../security_only/apis/delete.ts              |  313 +-
 .../security_only/apis/export.ts              |  299 +-
 .../security_only/apis/find.ts                |  791 +--
 .../security_only/apis/get.ts                 |  312 +-
 .../security_only/apis/import.ts              |  278 +-
 .../security_only/apis/index.ts               |    2 +-
 .../apis/resolve_import_errors.ts             |  277 +-
 .../security_only/apis/update.ts              |  314 +-
 .../spaces_only/apis/bulk_create.ts           |  123 +-
 .../spaces_only/apis/bulk_get.ts              |   68 +-
 .../spaces_only/apis/bulk_update.ts           |  110 +-
 .../spaces_only/apis/create.ts                |  118 +-
 .../spaces_only/apis/delete.ts                |  109 +-
 .../spaces_only/apis/export.ts                |   65 +-
 .../spaces_only/apis/find.ts                  |  157 +-
 .../spaces_only/apis/get.ts                   |  110 +-
 .../spaces_only/apis/import.ts                |   74 +-
 .../spaces_only/apis/index.ts                 |    2 +-
 .../spaces_only/apis/resolve_import_errors.ts |   85 +-
 .../spaces_only/apis/update.ts                |  110 +-
 .../spaces_api_integration/common/config.ts   |    1 +
 .../saved_objects/spaces/data.json            |  120 +
 .../saved_objects/spaces/mappings.json        |   16 +
 .../fixtures/shared_type_plugin/index.js      |   27 +
 .../fixtures/shared_type_plugin/mappings.json |   15 +
 .../fixtures/shared_type_plugin/package.json  |    7 +
 .../common/lib/saved_object_test_cases.ts     |   40 +
 .../common/suites/delete.ts                   |   20 +
 .../common/suites/share_add.ts                |  118 +
 .../common/suites/share_remove.ts             |  116 +
 .../security_and_spaces/apis/index.ts         |    2 +
 .../security_and_spaces/apis/share_add.ts     |  124 +
 .../security_and_spaces/apis/share_remove.ts  |   99 +
 .../spaces_only/apis/index.ts                 |    2 +
 .../spaces_only/apis/share_add.ts             |   84 +
 .../spaces_only/apis/share_remove.ts          |   99 +
 185 files changed, 12261 insertions(+), 15549 deletions(-)
 create mode 100644 docs/development/core/public/kibana-plugin-core-public.savedobject.namespaces.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobject.namespaces.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.refresh.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.version.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.addtonamespaces.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.refresh.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decorateescannotexecutescripterror.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsnamespacetype.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespacetype.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.ismultinamespace.md
 create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.issinglenamespace.md
 delete mode 100644 src/core/server/saved_objects/service/lib/__snapshots__/repository.test.js.snap
 delete mode 100644 x-pack/plugins/security/server/authorization/__snapshots__/check_privileges.test.ts.snap
 create mode 100644 x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts
 create mode 100644 x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts
 delete mode 100644 x-pack/plugins/spaces/server/saved_objects/__snapshots__/spaces_saved_objects_client.test.ts.snap
 create mode 100644 x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/index.js
 create mode 100644 x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/mappings.json
 create mode 100644 x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/package.json
 create mode 100644 x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/index.js
 create mode 100644 x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/mappings.json
 create mode 100644 x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/package.json
 create mode 100644 x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts
 create mode 100644 x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts
 delete mode 100644 x-pack/test/saved_object_api_integration/common/lib/space_test_utils.ts
 create mode 100644 x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/index.js
 create mode 100644 x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/mappings.json
 create mode 100644 x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/package.json
 create mode 100644 x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts
 create mode 100644 x-pack/test/spaces_api_integration/common/suites/share_add.ts
 create mode 100644 x-pack/test/spaces_api_integration/common/suites/share_remove.ts
 create mode 100644 x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts
 create mode 100644 x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts
 create mode 100644 x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts
 create mode 100644 x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts

diff --git a/docs/api/saved-objects/bulk_create.asciidoc b/docs/api/saved-objects/bulk_create.asciidoc
index 9daba224b317c..fbd4c6e77f8bf 100644
--- a/docs/api/saved-objects/bulk_create.asciidoc
+++ b/docs/api/saved-objects/bulk_create.asciidoc
@@ -104,7 +104,7 @@ The API returns the following:
       "type": "dashboard",
       "error": {
         "statusCode": 409,
-        "message": "version conflict, document already exists"
+        "message": "Saved object [dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab] conflict"
       }
     }
   ]
diff --git a/docs/development/core/public/kibana-plugin-core-public.savedobject.md b/docs/development/core/public/kibana-plugin-core-public.savedobject.md
index c6bc13b98bc06..b67d0536fb336 100644
--- a/docs/development/core/public/kibana-plugin-core-public.savedobject.md
+++ b/docs/development/core/public/kibana-plugin-core-public.savedobject.md
@@ -18,6 +18,7 @@ export interface SavedObject<T = unknown>
 |  [error](./kibana-plugin-core-public.savedobject.error.md) | <code>{</code><br/><code>        message: string;</code><br/><code>        statusCode: number;</code><br/><code>    }</code> |  |
 |  [id](./kibana-plugin-core-public.savedobject.id.md) | <code>string</code> | The ID of this Saved Object, guaranteed to be unique for all objects of the same <code>type</code> |
 |  [migrationVersion](./kibana-plugin-core-public.savedobject.migrationversion.md) | <code>SavedObjectsMigrationVersion</code> | Information about the migrations that have been applied to this SavedObject. When Kibana starts up, KibanaMigrator detects outdated documents and migrates them based on this value. For each migration that has been applied, the plugin's name is used as a key and the latest migration version as the value. |
+|  [namespaces](./kibana-plugin-core-public.savedobject.namespaces.md) | <code>string[]</code> | Namespace(s) that this saved object exists in. This attribute is only used for multi-namespace saved object types. |
 |  [references](./kibana-plugin-core-public.savedobject.references.md) | <code>SavedObjectReference[]</code> | A reference to another saved object. |
 |  [type](./kibana-plugin-core-public.savedobject.type.md) | <code>string</code> | The type of Saved Object. Each plugin can define it's own custom Saved Object types. |
 |  [updated\_at](./kibana-plugin-core-public.savedobject.updated_at.md) | <code>string</code> | Timestamp of the last time this document had been updated. |
diff --git a/docs/development/core/public/kibana-plugin-core-public.savedobject.namespaces.md b/docs/development/core/public/kibana-plugin-core-public.savedobject.namespaces.md
new file mode 100644
index 0000000000000..257df45934506
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.savedobject.namespaces.md
@@ -0,0 +1,13 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-public](./kibana-plugin-core-public.md) &gt; [SavedObject](./kibana-plugin-core-public.savedobject.md) &gt; [namespaces](./kibana-plugin-core-public.savedobject.namespaces.md)
+
+## SavedObject.namespaces property
+
+Namespace(s) that this saved object exists in. This attribute is only used for multi-namespace saved object types.
+
+<b>Signature:</b>
+
+```typescript
+namespaces?: string[];
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.isavedobjecttyperegistry.md b/docs/development/core/server/kibana-plugin-core-server.isavedobjecttyperegistry.md
index 245cb1a56439f..f9c621885c001 100644
--- a/docs/development/core/server/kibana-plugin-core-server.isavedobjecttyperegistry.md
+++ b/docs/development/core/server/kibana-plugin-core-server.isavedobjecttyperegistry.md
@@ -9,5 +9,5 @@ See [SavedObjectTypeRegistry](./kibana-plugin-core-server.savedobjecttyperegistr
 <b>Signature:</b>
 
 ```typescript
-export declare type ISavedObjectTypeRegistry = Pick<SavedObjectTypeRegistry, 'getType' | 'getAllTypes' | 'getIndex' | 'isNamespaceAgnostic' | 'isHidden' | 'getImportableAndExportableTypes' | 'isImportableAndExportable'>;
+export declare type ISavedObjectTypeRegistry = Omit<SavedObjectTypeRegistry, 'registerType'>;
 ```
diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md
index accab9bf0cb36..5c0f10cac5179 100644
--- a/docs/development/core/server/kibana-plugin-core-server.md
+++ b/docs/development/core/server/kibana-plugin-core-server.md
@@ -130,6 +130,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
 |  [SavedObjectMigrationContext](./kibana-plugin-core-server.savedobjectmigrationcontext.md) | Migration context provided when invoking a [migration handler](./kibana-plugin-core-server.savedobjectmigrationfn.md) |
 |  [SavedObjectMigrationMap](./kibana-plugin-core-server.savedobjectmigrationmap.md) | A map of [migration functions](./kibana-plugin-core-server.savedobjectmigrationfn.md) to be used for a given type. The map's keys must be valid semver versions.<!-- -->For a given document, only migrations with a higher version number than that of the document will be applied. Migrations are executed in order, starting from the lowest version and ending with the highest one. |
 |  [SavedObjectReference](./kibana-plugin-core-server.savedobjectreference.md) | A reference to another saved object. |
+|  [SavedObjectsAddToNamespacesOptions](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md) |  |
 |  [SavedObjectsBaseOptions](./kibana-plugin-core-server.savedobjectsbaseoptions.md) |  |
 |  [SavedObjectsBulkCreateObject](./kibana-plugin-core-server.savedobjectsbulkcreateobject.md) |  |
 |  [SavedObjectsBulkGetObject](./kibana-plugin-core-server.savedobjectsbulkgetobject.md) |  |
@@ -143,6 +144,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
 |  [SavedObjectsCoreFieldMapping](./kibana-plugin-core-server.savedobjectscorefieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation. |
 |  [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md) |  |
 |  [SavedObjectsDeleteByNamespaceOptions](./kibana-plugin-core-server.savedobjectsdeletebynamespaceoptions.md) |  |
+|  [SavedObjectsDeleteFromNamespacesOptions](./kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md) |  |
 |  [SavedObjectsDeleteOptions](./kibana-plugin-core-server.savedobjectsdeleteoptions.md) |  |
 |  [SavedObjectsExportOptions](./kibana-plugin-core-server.savedobjectsexportoptions.md) | Options controlling the export operation. |
 |  [SavedObjectsExportResultDetails](./kibana-plugin-core-server.savedobjectsexportresultdetails.md) | Structure of the export result details entry |
@@ -262,6 +264,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
 |  [SavedObjectsClientFactoryProvider](./kibana-plugin-core-server.savedobjectsclientfactoryprovider.md) | Provider to invoke to retrieve a [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md)<!-- -->. |
 |  [SavedObjectsClientWrapperFactory](./kibana-plugin-core-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. |
 |  [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) | Describe a [saved object type mapping](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) field.<!-- -->Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) For the mapping documentation |
+|  [SavedObjectsNamespaceType](./kibana-plugin-core-server.savedobjectsnamespacetype.md) | The namespace type dictates how a saved object can be interacted in relation to namespaces. Each type is mutually exclusive: \* single (default): this type of saved object is namespace-isolated, e.g., it exists in only one namespace. \* multiple: this type of saved object is shareable, e.g., it can exist in one or more namespaces. \* agnostic: this type of saved object is global.<!-- -->Note: do not write logic that uses this value directly; instead, use the appropriate accessors in the [type registry](./kibana-plugin-core-server.savedobjecttyperegistry.md)<!-- -->. |
 |  [ScopeableRequest](./kibana-plugin-core-server.scopeablerequest.md) | A user credentials container. It accommodates the necessary auth credentials to impersonate the current user.<!-- -->See [KibanaRequest](./kibana-plugin-core-server.kibanarequest.md)<!-- -->. |
 |  [ServiceStatusLevel](./kibana-plugin-core-server.servicestatuslevel.md) | A convenience type that represents the union of each value in [ServiceStatusLevels](./kibana-plugin-core-server.servicestatuslevels.md)<!-- -->. |
 |  [SharedGlobalConfig](./kibana-plugin-core-server.sharedglobalconfig.md) |  |
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobject.md b/docs/development/core/server/kibana-plugin-core-server.savedobject.md
index 0df97b0d4221a..94d1c378899df 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobject.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobject.md
@@ -18,6 +18,7 @@ export interface SavedObject<T = unknown>
 |  [error](./kibana-plugin-core-server.savedobject.error.md) | <code>{</code><br/><code>        message: string;</code><br/><code>        statusCode: number;</code><br/><code>    }</code> |  |
 |  [id](./kibana-plugin-core-server.savedobject.id.md) | <code>string</code> | The ID of this Saved Object, guaranteed to be unique for all objects of the same <code>type</code> |
 |  [migrationVersion](./kibana-plugin-core-server.savedobject.migrationversion.md) | <code>SavedObjectsMigrationVersion</code> | Information about the migrations that have been applied to this SavedObject. When Kibana starts up, KibanaMigrator detects outdated documents and migrates them based on this value. For each migration that has been applied, the plugin's name is used as a key and the latest migration version as the value. |
+|  [namespaces](./kibana-plugin-core-server.savedobject.namespaces.md) | <code>string[]</code> | Namespace(s) that this saved object exists in. This attribute is only used for multi-namespace saved object types. |
 |  [references](./kibana-plugin-core-server.savedobject.references.md) | <code>SavedObjectReference[]</code> | A reference to another saved object. |
 |  [type](./kibana-plugin-core-server.savedobject.type.md) | <code>string</code> | The type of Saved Object. Each plugin can define it's own custom Saved Object types. |
 |  [updated\_at](./kibana-plugin-core-server.savedobject.updated_at.md) | <code>string</code> | Timestamp of the last time this document had been updated. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobject.namespaces.md b/docs/development/core/server/kibana-plugin-core-server.savedobject.namespaces.md
new file mode 100644
index 0000000000000..2a555db01df3b
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobject.namespaces.md
@@ -0,0 +1,13 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObject](./kibana-plugin-core-server.savedobject.md) &gt; [namespaces](./kibana-plugin-core-server.savedobject.namespaces.md)
+
+## SavedObject.namespaces property
+
+Namespace(s) that this saved object exists in. This attribute is only used for multi-namespace saved object types.
+
+<b>Signature:</b>
+
+```typescript
+namespaces?: string[];
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md
new file mode 100644
index 0000000000000..711588bdd608c
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md
@@ -0,0 +1,20 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsAddToNamespacesOptions](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md)
+
+## SavedObjectsAddToNamespacesOptions interface
+
+
+<b>Signature:</b>
+
+```typescript
+export interface SavedObjectsAddToNamespacesOptions extends SavedObjectsBaseOptions 
+```
+
+## Properties
+
+|  Property | Type | Description |
+|  --- | --- | --- |
+|  [refresh](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.refresh.md) | <code>MutatingOperationRefreshSetting</code> | The Elasticsearch Refresh setting for this operation |
+|  [version](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.version.md) | <code>string</code> | An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. |
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.refresh.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.refresh.md
new file mode 100644
index 0000000000000..c0a1008ab5331
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.refresh.md
@@ -0,0 +1,13 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsAddToNamespacesOptions](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md) &gt; [refresh](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.refresh.md)
+
+## SavedObjectsAddToNamespacesOptions.refresh property
+
+The Elasticsearch Refresh setting for this operation
+
+<b>Signature:</b>
+
+```typescript
+refresh?: MutatingOperationRefreshSetting;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.version.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.version.md
new file mode 100644
index 0000000000000..9432b4bf80da6
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.version.md
@@ -0,0 +1,13 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsAddToNamespacesOptions](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.md) &gt; [version](./kibana-plugin-core-server.savedobjectsaddtonamespacesoptions.version.md)
+
+## SavedObjectsAddToNamespacesOptions.version property
+
+An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control.
+
+<b>Signature:</b>
+
+```typescript
+version?: string;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.addtonamespaces.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.addtonamespaces.md
new file mode 100644
index 0000000000000..45c9c39f9626a
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.addtonamespaces.md
@@ -0,0 +1,27 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) &gt; [addToNamespaces](./kibana-plugin-core-server.savedobjectsclient.addtonamespaces.md)
+
+## SavedObjectsClient.addToNamespaces() method
+
+Adds namespaces to a SavedObject
+
+<b>Signature:</b>
+
+```typescript
+addToNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsAddToNamespacesOptions): Promise<{}>;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+|  id | <code>string</code> |  |
+|  namespaces | <code>string[]</code> |  |
+|  options | <code>SavedObjectsAddToNamespacesOptions</code> |  |
+
+<b>Returns:</b>
+
+`Promise<{}>`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md
new file mode 100644
index 0000000000000..80b58d29d393b
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md
@@ -0,0 +1,27 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) &gt; [deleteFromNamespaces](./kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md)
+
+## SavedObjectsClient.deleteFromNamespaces() method
+
+Removes namespaces from a SavedObject
+
+<b>Signature:</b>
+
+```typescript
+deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<{}>;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+|  id | <code>string</code> |  |
+|  namespaces | <code>string[]</code> |  |
+|  options | <code>SavedObjectsDeleteFromNamespacesOptions</code> |  |
+
+<b>Returns:</b>
+
+`Promise<{}>`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.md
index 5a8a213d2bccc..7038c0c07012f 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclient.md
@@ -25,11 +25,13 @@ The constructor for this class is marked as internal. Third-party code should no
 
 |  Method | Modifiers | Description |
 |  --- | --- | --- |
+|  [addToNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsclient.addtonamespaces.md) |  | Adds namespaces to a SavedObject |
 |  [bulkCreate(objects, options)](./kibana-plugin-core-server.savedobjectsclient.bulkcreate.md) |  | Persists multiple documents batched together as a single request |
 |  [bulkGet(objects, options)](./kibana-plugin-core-server.savedobjectsclient.bulkget.md) |  | Returns an array of objects by id |
 |  [bulkUpdate(objects, options)](./kibana-plugin-core-server.savedobjectsclient.bulkupdate.md) |  | Bulk Updates multiple SavedObject at once |
 |  [create(type, attributes, options)](./kibana-plugin-core-server.savedobjectsclient.create.md) |  | Persists a SavedObject |
 |  [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsclient.delete.md) |  | Deletes a SavedObject |
+|  [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md) |  | Removes namespaces from a SavedObject |
 |  [find(options)](./kibana-plugin-core-server.savedobjectsclient.find.md) |  | Find all SavedObjects matching the search query |
 |  [get(type, id, options)](./kibana-plugin-core-server.savedobjectsclient.get.md) |  | Retrieves a single object |
 |  [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsclient.update.md) |  | Updates an SavedObject |
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md
new file mode 100644
index 0000000000000..8a2afe6656fa4
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md
@@ -0,0 +1,19 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsDeleteFromNamespacesOptions](./kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md)
+
+## SavedObjectsDeleteFromNamespacesOptions interface
+
+
+<b>Signature:</b>
+
+```typescript
+export interface SavedObjectsDeleteFromNamespacesOptions extends SavedObjectsBaseOptions 
+```
+
+## Properties
+
+|  Property | Type | Description |
+|  --- | --- | --- |
+|  [refresh](./kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.refresh.md) | <code>MutatingOperationRefreshSetting</code> | The Elasticsearch Refresh setting for this operation |
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.refresh.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.refresh.md
new file mode 100644
index 0000000000000..1175b79bc1abd
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.refresh.md
@@ -0,0 +1,13 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsDeleteFromNamespacesOptions](./kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.md) &gt; [refresh](./kibana-plugin-core-server.savedobjectsdeletefromnamespacesoptions.refresh.md)
+
+## SavedObjectsDeleteFromNamespacesOptions.refresh property
+
+The Elasticsearch Refresh setting for this operation
+
+<b>Signature:</b>
+
+```typescript
+refresh?: MutatingOperationRefreshSetting;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md
new file mode 100644
index 0000000000000..8e04282ce0c71
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md
@@ -0,0 +1,23 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) &gt; [createConflictError](./kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md)
+
+## SavedObjectsErrorHelpers.createConflictError() method
+
+<b>Signature:</b>
+
+```typescript
+static createConflictError(type: string, id: string): DecoratedError;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+|  id | <code>string</code> |  |
+
+<b>Returns:</b>
+
+`DecoratedError`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decorateescannotexecutescripterror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decorateescannotexecutescripterror.md
new file mode 100644
index 0000000000000..94060bba50067
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.decorateescannotexecutescripterror.md
@@ -0,0 +1,23 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) &gt; [decorateEsCannotExecuteScriptError](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateescannotexecutescripterror.md)
+
+## SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError() method
+
+<b>Signature:</b>
+
+```typescript
+static decorateEsCannotExecuteScriptError(error: Error, reason?: string): DecoratedError;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  error | <code>Error</code> |  |
+|  reason | <code>string</code> |  |
+
+<b>Returns:</b>
+
+`DecoratedError`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md
new file mode 100644
index 0000000000000..debb94fe4f8d8
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md
@@ -0,0 +1,22 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) &gt; [isEsCannotExecuteScriptError](./kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md)
+
+## SavedObjectsErrorHelpers.isEsCannotExecuteScriptError() method
+
+<b>Signature:</b>
+
+```typescript
+static isEsCannotExecuteScriptError(error: Error | DecoratedError): boolean;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  error | <code>Error &#124; DecoratedError</code> |  |
+
+<b>Returns:</b>
+
+`boolean`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md
index 55a42e4f4eb7a..250b9d3899670 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md
@@ -16,12 +16,14 @@ export declare class SavedObjectsErrorHelpers
 |  Method | Modifiers | Description |
 |  --- | --- | --- |
 |  [createBadRequestError(reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.createbadrequesterror.md) | <code>static</code> |  |
+|  [createConflictError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md) | <code>static</code> |  |
 |  [createEsAutoCreateIndexError()](./kibana-plugin-core-server.savedobjectserrorhelpers.createesautocreateindexerror.md) | <code>static</code> |  |
 |  [createGenericNotFoundError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfounderror.md) | <code>static</code> |  |
 |  [createInvalidVersionError(versionInput)](./kibana-plugin-core-server.savedobjectserrorhelpers.createinvalidversionerror.md) | <code>static</code> |  |
 |  [createUnsupportedTypeError(type)](./kibana-plugin-core-server.savedobjectserrorhelpers.createunsupportedtypeerror.md) | <code>static</code> |  |
 |  [decorateBadRequestError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratebadrequesterror.md) | <code>static</code> |  |
 |  [decorateConflictError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateconflicterror.md) | <code>static</code> |  |
+|  [decorateEsCannotExecuteScriptError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateescannotexecutescripterror.md) | <code>static</code> |  |
 |  [decorateEsUnavailableError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateesunavailableerror.md) | <code>static</code> |  |
 |  [decorateForbiddenError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateforbiddenerror.md) | <code>static</code> |  |
 |  [decorateGeneralError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorategeneralerror.md) | <code>static</code> |  |
@@ -30,6 +32,7 @@ export declare class SavedObjectsErrorHelpers
 |  [isBadRequestError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isbadrequesterror.md) | <code>static</code> |  |
 |  [isConflictError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isconflicterror.md) | <code>static</code> |  |
 |  [isEsAutoCreateIndexError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isesautocreateindexerror.md) | <code>static</code> |  |
+|  [isEsCannotExecuteScriptError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md) | <code>static</code> |  |
 |  [isEsUnavailableError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isesunavailableerror.md) | <code>static</code> |  |
 |  [isForbiddenError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isforbiddenerror.md) | <code>static</code> |  |
 |  [isInvalidVersionError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isinvalidversionerror.md) | <code>static</code> |  |
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsnamespacetype.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsnamespacetype.md
new file mode 100644
index 0000000000000..173b9e19321d0
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsnamespacetype.md
@@ -0,0 +1,15 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsNamespaceType](./kibana-plugin-core-server.savedobjectsnamespacetype.md)
+
+## SavedObjectsNamespaceType type
+
+The namespace type dictates how a saved object can be interacted in relation to namespaces. Each type is mutually exclusive: \* single (default): this type of saved object is namespace-isolated, e.g., it exists in only one namespace. \* multiple: this type of saved object is shareable, e.g., it can exist in one or more namespaces. \* agnostic: this type of saved object is global.
+
+Note: do not write logic that uses this value directly; instead, use the appropriate accessors in the [type registry](./kibana-plugin-core-server.savedobjecttyperegistry.md)<!-- -->.
+
+<b>Signature:</b>
+
+```typescript
+export declare type SavedObjectsNamespaceType = 'single' | 'multiple' | 'agnostic';
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md
new file mode 100644
index 0000000000000..bbb20d2bc3b96
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md
@@ -0,0 +1,27 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) &gt; [addToNamespaces](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md)
+
+## SavedObjectsRepository.addToNamespaces() method
+
+Adds one or more namespaces to a given multi-namespace saved object. This method and \[`deleteFromNamespaces`<!-- -->\][SavedObjectsRepository.deleteFromNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to.
+
+<b>Signature:</b>
+
+```typescript
+addToNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsAddToNamespacesOptions): Promise<{}>;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+|  id | <code>string</code> |  |
+|  namespaces | <code>string[]</code> |  |
+|  options | <code>SavedObjectsAddToNamespacesOptions</code> |  |
+
+<b>Returns:</b>
+
+`Promise<{}>`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md
new file mode 100644
index 0000000000000..471c3e3c5092d
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md
@@ -0,0 +1,27 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) &gt; [deleteFromNamespaces](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md)
+
+## SavedObjectsRepository.deleteFromNamespaces() method
+
+Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted entirely. This method and \[`addToNamespaces`<!-- -->\][SavedObjectsRepository.addToNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to.
+
+<b>Signature:</b>
+
+```typescript
+deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<{}>;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+|  id | <code>string</code> |  |
+|  namespaces | <code>string[]</code> |  |
+|  options | <code>SavedObjectsDeleteFromNamespacesOptions</code> |  |
+
+<b>Returns:</b>
+
+`Promise<{}>`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md
index 37547af2497e9..bd86ff3abbe9b 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md
@@ -15,12 +15,14 @@ export declare class SavedObjectsRepository
 
 |  Method | Modifiers | Description |
 |  --- | --- | --- |
+|  [addToNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) |  | Adds one or more namespaces to a given multi-namespace saved object. This method and \[<code>deleteFromNamespaces</code>\][SavedObjectsRepository.deleteFromNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to. |
 |  [bulkCreate(objects, options)](./kibana-plugin-core-server.savedobjectsrepository.bulkcreate.md) |  | Creates multiple documents at once |
 |  [bulkGet(objects, options)](./kibana-plugin-core-server.savedobjectsrepository.bulkget.md) |  | Returns an array of objects by id |
 |  [bulkUpdate(objects, options)](./kibana-plugin-core-server.savedobjectsrepository.bulkupdate.md) |  | Updates multiple objects in bulk |
 |  [create(type, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.create.md) |  | Persists an object |
 |  [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.delete.md) |  | Deletes an object |
 |  [deleteByNamespace(namespace, options)](./kibana-plugin-core-server.savedobjectsrepository.deletebynamespace.md) |  | Deletes all objects from the provided namespace. |
+|  [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) |  | Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted entirely. This method and \[<code>addToNamespaces</code>\][SavedObjectsRepository.addToNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to. |
 |  [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) |  |  |
 |  [get(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.get.md) |  | Gets a single object |
 |  [incrementCounter(type, id, counterFieldName, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) |  | Increases a counter field by one. Creates the document if one doesn't exist for the given id. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md
index c24fa7e7038c6..57c9e04966c1b 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md
@@ -29,7 +29,7 @@ import * as migrations from './migrations';
 export const myType: SavedObjectsType = {
   name: 'MyType',
   hidden: false,
-  namespaceAgnostic: true,
+  namespaceType: 'multiple',
   mappings: {
     properties: {
       textField: {
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.md
index ad7bf9a0f00d0..d8202545f0eae 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.md
@@ -25,5 +25,6 @@ This is only internal for now, and will only be public when we expose the regist
 |  [mappings](./kibana-plugin-core-server.savedobjectstype.mappings.md) | <code>SavedObjectsTypeMappingDefinition</code> | The [mapping definition](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) for the type. |
 |  [migrations](./kibana-plugin-core-server.savedobjectstype.migrations.md) | <code>SavedObjectMigrationMap</code> | An optional map of [migrations](./kibana-plugin-core-server.savedobjectmigrationfn.md) to be used to migrate the type. |
 |  [name](./kibana-plugin-core-server.savedobjectstype.name.md) | <code>string</code> | The name of the type, which is also used as the internal id. |
-|  [namespaceAgnostic](./kibana-plugin-core-server.savedobjectstype.namespaceagnostic.md) | <code>boolean</code> | Is the type global (true), or namespaced (false). |
+|  [namespaceAgnostic](./kibana-plugin-core-server.savedobjectstype.namespaceagnostic.md) | <code>boolean</code> | Is the type global (true), or not (false). |
+|  [namespaceType](./kibana-plugin-core-server.savedobjectstype.namespacetype.md) | <code>SavedObjectsNamespaceType</code> | The [namespace type](./kibana-plugin-core-server.savedobjectsnamespacetype.md) for the type. |
 
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespaceagnostic.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespaceagnostic.md
index 8f43db86449d0..e347421590482 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespaceagnostic.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespaceagnostic.md
@@ -4,10 +4,15 @@
 
 ## SavedObjectsType.namespaceAgnostic property
 
-Is the type global (true), or namespaced (false).
+> Warning: This API is now obsolete.
+> 
+> Use `namespaceType` instead.
+> 
+
+Is the type global (true), or not (false).
 
 <b>Signature:</b>
 
 ```typescript
-namespaceAgnostic: boolean;
+namespaceAgnostic?: boolean;
 ```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespacetype.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespacetype.md
new file mode 100644
index 0000000000000..69912f9144980
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstype.namespacetype.md
@@ -0,0 +1,13 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsType](./kibana-plugin-core-server.savedobjectstype.md) &gt; [namespaceType](./kibana-plugin-core-server.savedobjectstype.namespacetype.md)
+
+## SavedObjectsType.namespaceType property
+
+The [namespace type](./kibana-plugin-core-server.savedobjectsnamespacetype.md) for the type.
+
+<b>Signature:</b>
+
+```typescript
+namespaceType?: SavedObjectsNamespaceType;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.ismultinamespace.md b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.ismultinamespace.md
new file mode 100644
index 0000000000000..6532c5251d816
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.ismultinamespace.md
@@ -0,0 +1,24 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectTypeRegistry](./kibana-plugin-core-server.savedobjecttyperegistry.md) &gt; [isMultiNamespace](./kibana-plugin-core-server.savedobjecttyperegistry.ismultinamespace.md)
+
+## SavedObjectTypeRegistry.isMultiNamespace() method
+
+Returns whether the type is multi-namespace (shareable); resolves to `false` if the type is not registered
+
+<b>Signature:</b>
+
+```typescript
+isMultiNamespace(type: string): boolean;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+
+<b>Returns:</b>
+
+`boolean`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.isnamespaceagnostic.md b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.isnamespaceagnostic.md
index 92dfa5465235a..859c7b9711816 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.isnamespaceagnostic.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.isnamespaceagnostic.md
@@ -4,7 +4,7 @@
 
 ## SavedObjectTypeRegistry.isNamespaceAgnostic() method
 
-Returns the `namespaceAgnostic` property for given type, or `false` if the type is not registered.
+Returns whether the type is namespace-agnostic (global); resolves to `false` if the type is not registered
 
 <b>Signature:</b>
 
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.issinglenamespace.md b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.issinglenamespace.md
new file mode 100644
index 0000000000000..18146b2fd6ea1
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.issinglenamespace.md
@@ -0,0 +1,24 @@
+<!-- Do not edit this file. It is automatically generated by API Documenter. -->
+
+[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectTypeRegistry](./kibana-plugin-core-server.savedobjecttyperegistry.md) &gt; [isSingleNamespace](./kibana-plugin-core-server.savedobjecttyperegistry.issinglenamespace.md)
+
+## SavedObjectTypeRegistry.isSingleNamespace() method
+
+Returns whether the type is single-namespace (isolated); resolves to `true` if the type is not registered
+
+<b>Signature:</b>
+
+```typescript
+isSingleNamespace(type: string): boolean;
+```
+
+## Parameters
+
+|  Parameter | Type | Description |
+|  --- | --- | --- |
+|  type | <code>string</code> |  |
+
+<b>Returns:</b>
+
+`boolean`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.md b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.md
index 410b709252b72..69a94e4ad8c88 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjecttyperegistry.md
@@ -22,6 +22,8 @@ export declare class SavedObjectTypeRegistry
 |  [getType(type)](./kibana-plugin-core-server.savedobjecttyperegistry.gettype.md) |  | Return the [type](./kibana-plugin-core-server.savedobjectstype.md) definition for given type name. |
 |  [isHidden(type)](./kibana-plugin-core-server.savedobjecttyperegistry.ishidden.md) |  | Returns the <code>hidden</code> property for given type, or <code>false</code> if the type is not registered. |
 |  [isImportableAndExportable(type)](./kibana-plugin-core-server.savedobjecttyperegistry.isimportableandexportable.md) |  | Returns the <code>management.importableAndExportable</code> property for given type, or <code>false</code> if the type is not registered or does not define a management section. |
-|  [isNamespaceAgnostic(type)](./kibana-plugin-core-server.savedobjecttyperegistry.isnamespaceagnostic.md) |  | Returns the <code>namespaceAgnostic</code> property for given type, or <code>false</code> if the type is not registered. |
+|  [isMultiNamespace(type)](./kibana-plugin-core-server.savedobjecttyperegistry.ismultinamespace.md) |  | Returns whether the type is multi-namespace (shareable); resolves to <code>false</code> if the type is not registered |
+|  [isNamespaceAgnostic(type)](./kibana-plugin-core-server.savedobjecttyperegistry.isnamespaceagnostic.md) |  | Returns whether the type is namespace-agnostic (global); resolves to <code>false</code> if the type is not registered |
+|  [isSingleNamespace(type)](./kibana-plugin-core-server.savedobjecttyperegistry.issinglenamespace.md) |  | Returns whether the type is single-namespace (isolated); resolves to <code>true</code> if the type is not registered |
 |  [registerType(type)](./kibana-plugin-core-server.savedobjecttyperegistry.registertype.md) |  | Register a [type](./kibana-plugin-core-server.savedobjectstype.md) inside the registry. A type can only be registered once. subsequent calls with the same type name will throw an error. |
 
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index 9f7f649f1e2a5..a5aa37becabc2 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -956,6 +956,7 @@ export interface SavedObject<T = unknown> {
     };
     id: string;
     migrationVersion?: SavedObjectsMigrationVersion;
+    namespaces?: string[];
     references: SavedObjectReference[];
     type: string;
     updated_at?: string;
diff --git a/src/core/server/index.ts b/src/core/server/index.ts
index a298f80f96d8f..039988fa08968 100644
--- a/src/core/server/index.ts
+++ b/src/core/server/index.ts
@@ -227,6 +227,8 @@ export {
   SavedObjectsLegacyService,
   SavedObjectsUpdateOptions,
   SavedObjectsUpdateResponse,
+  SavedObjectsAddToNamespacesOptions,
+  SavedObjectsDeleteFromNamespacesOptions,
   SavedObjectsServiceStart,
   SavedObjectsServiceSetup,
   SavedObjectStatusMeta,
@@ -242,6 +244,7 @@ export {
   SavedObjectsMappingProperties,
   SavedObjectTypeRegistry,
   ISavedObjectTypeRegistry,
+  SavedObjectsNamespaceType,
   SavedObjectsType,
   SavedObjectsTypeManagementDefinition,
   SavedObjectMigrationMap,
diff --git a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap
index 5431d2ca47892..7cd0297e57857 100644
--- a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap
+++ b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap
@@ -16,7 +16,7 @@ Array [
     },
     "migrations": Object {},
     "name": "typeA",
-    "namespaceAgnostic": false,
+    "namespaceType": "single",
   },
   Object {
     "convertToAliasScript": undefined,
@@ -32,7 +32,7 @@ Array [
     },
     "migrations": Object {},
     "name": "typeB",
-    "namespaceAgnostic": false,
+    "namespaceType": "single",
   },
   Object {
     "convertToAliasScript": undefined,
@@ -48,7 +48,7 @@ Array [
     },
     "migrations": Object {},
     "name": "typeC",
-    "namespaceAgnostic": false,
+    "namespaceType": "single",
   },
 ]
 `;
@@ -72,7 +72,7 @@ Array [
       "2.0.4": [Function],
     },
     "name": "typeA",
-    "namespaceAgnostic": true,
+    "namespaceType": "agnostic",
   },
   Object {
     "convertToAliasScript": "some alias script",
@@ -91,7 +91,7 @@ Array [
     },
     "migrations": Object {},
     "name": "typeB",
-    "namespaceAgnostic": false,
+    "namespaceType": "single",
   },
   Object {
     "convertToAliasScript": undefined,
@@ -109,7 +109,7 @@ Array [
       "1.5.3": [Function],
     },
     "name": "typeC",
-    "namespaceAgnostic": false,
+    "namespaceType": "single",
   },
 ]
 `;
@@ -130,7 +130,23 @@ Array [
     },
     "migrations": Object {},
     "name": "typeA",
-    "namespaceAgnostic": true,
+    "namespaceType": "agnostic",
+  },
+  Object {
+    "convertToAliasScript": undefined,
+    "hidden": false,
+    "indexPattern": "barBaz",
+    "management": undefined,
+    "mappings": Object {
+      "properties": Object {
+        "fieldB": Object {
+          "type": "text",
+        },
+      },
+    },
+    "migrations": Object {},
+    "name": "typeB",
+    "namespaceType": "multiple",
   },
   Object {
     "convertToAliasScript": undefined,
@@ -146,7 +162,23 @@ Array [
     },
     "migrations": Object {},
     "name": "typeC",
-    "namespaceAgnostic": false,
+    "namespaceType": "single",
+  },
+  Object {
+    "convertToAliasScript": undefined,
+    "hidden": false,
+    "indexPattern": "bazQux",
+    "management": undefined,
+    "mappings": Object {
+      "properties": Object {
+        "fieldD": Object {
+          "type": "text",
+        },
+      },
+    },
+    "migrations": Object {},
+    "name": "typeD",
+    "namespaceType": "agnostic",
   },
 ]
 `;
diff --git a/src/core/server/saved_objects/index.ts b/src/core/server/saved_objects/index.ts
index fe4795cad11a5..a294b28753f7b 100644
--- a/src/core/server/saved_objects/index.ts
+++ b/src/core/server/saved_objects/index.ts
@@ -69,6 +69,7 @@ export {
 } from './migrations';
 
 export {
+  SavedObjectsNamespaceType,
   SavedObjectStatusMeta,
   SavedObjectsType,
   SavedObjectsTypeManagementDefinition,
diff --git a/src/core/server/saved_objects/migrations/core/__snapshots__/build_active_mappings.test.ts.snap b/src/core/server/saved_objects/migrations/core/__snapshots__/build_active_mappings.test.ts.snap
index fc26d7e9cf6e9..bc9a66926e880 100644
--- a/src/core/server/saved_objects/migrations/core/__snapshots__/build_active_mappings.test.ts.snap
+++ b/src/core/server/saved_objects/migrations/core/__snapshots__/build_active_mappings.test.ts.snap
@@ -8,6 +8,7 @@ Object {
       "bbb": "18c78c995965207ed3f6e7fc5c6e55fe",
       "migrationVersion": "4a1746014a75ade3a714e1db5763276f",
       "namespace": "2f4316de49999235636386fe51dc06c1",
+      "namespaces": "2f4316de49999235636386fe51dc06c1",
       "references": "7997cf5a56cc02bdc9c93361bde732b0",
       "type": "2f4316de49999235636386fe51dc06c1",
       "updated_at": "00da57df13e94e9d98437d13ace4bfe0",
@@ -28,6 +29,9 @@ Object {
     "namespace": Object {
       "type": "keyword",
     },
+    "namespaces": Object {
+      "type": "keyword",
+    },
     "references": Object {
       "properties": Object {
         "id": Object {
@@ -59,6 +63,7 @@ Object {
       "firstType": "635418ab953d81d93f1190b70a8d3f57",
       "migrationVersion": "4a1746014a75ade3a714e1db5763276f",
       "namespace": "2f4316de49999235636386fe51dc06c1",
+      "namespaces": "2f4316de49999235636386fe51dc06c1",
       "references": "7997cf5a56cc02bdc9c93361bde732b0",
       "secondType": "72d57924f415fbadb3ee293b67d233ab",
       "thirdType": "510f1f0adb69830cf8a1c5ce2923ed82",
@@ -83,6 +88,9 @@ Object {
     "namespace": Object {
       "type": "keyword",
     },
+    "namespaces": Object {
+      "type": "keyword",
+    },
     "references": Object {
       "properties": Object {
         "id": Object {
diff --git a/src/core/server/saved_objects/migrations/core/build_active_mappings.ts b/src/core/server/saved_objects/migrations/core/build_active_mappings.ts
index 4d1a607414ca6..418ed95f14e05 100644
--- a/src/core/server/saved_objects/migrations/core/build_active_mappings.ts
+++ b/src/core/server/saved_objects/migrations/core/build_active_mappings.ts
@@ -142,6 +142,9 @@ function defaultMapping(): IndexMapping {
       namespace: {
         type: 'keyword',
       },
+      namespaces: {
+        type: 'keyword',
+      },
       updated_at: {
         type: 'date',
       },
diff --git a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts
index 1c2d3f501ff80..19208e6c83596 100644
--- a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts
+++ b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts
@@ -61,6 +61,7 @@ describe('IndexMigrator', () => {
               foo: '18c78c995965207ed3f6e7fc5c6e55fe',
               migrationVersion: '4a1746014a75ade3a714e1db5763276f',
               namespace: '2f4316de49999235636386fe51dc06c1',
+              namespaces: '2f4316de49999235636386fe51dc06c1',
               references: '7997cf5a56cc02bdc9c93361bde732b0',
               type: '2f4316de49999235636386fe51dc06c1',
               updated_at: '00da57df13e94e9d98437d13ace4bfe0',
@@ -70,6 +71,7 @@ describe('IndexMigrator', () => {
             foo: { type: 'long' },
             migrationVersion: { dynamic: 'true', type: 'object' },
             namespace: { type: 'keyword' },
+            namespaces: { type: 'keyword' },
             type: { type: 'keyword' },
             updated_at: { type: 'date' },
             references: {
@@ -178,6 +180,7 @@ describe('IndexMigrator', () => {
               foo: '625b32086eb1d1203564cf85062dd22e',
               migrationVersion: '4a1746014a75ade3a714e1db5763276f',
               namespace: '2f4316de49999235636386fe51dc06c1',
+              namespaces: '2f4316de49999235636386fe51dc06c1',
               references: '7997cf5a56cc02bdc9c93361bde732b0',
               type: '2f4316de49999235636386fe51dc06c1',
               updated_at: '00da57df13e94e9d98437d13ace4bfe0',
@@ -188,6 +191,7 @@ describe('IndexMigrator', () => {
             foo: { type: 'text' },
             migrationVersion: { dynamic: 'true', type: 'object' },
             namespace: { type: 'keyword' },
+            namespaces: { type: 'keyword' },
             type: { type: 'keyword' },
             updated_at: { type: 'date' },
             references: {
diff --git a/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap b/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap
index 507c0b0d9339f..3453f3fc80310 100644
--- a/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap
+++ b/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap
@@ -8,6 +8,7 @@ Object {
       "bmap": "510f1f0adb69830cf8a1c5ce2923ed82",
       "migrationVersion": "4a1746014a75ade3a714e1db5763276f",
       "namespace": "2f4316de49999235636386fe51dc06c1",
+      "namespaces": "2f4316de49999235636386fe51dc06c1",
       "references": "7997cf5a56cc02bdc9c93361bde732b0",
       "type": "2f4316de49999235636386fe51dc06c1",
       "updated_at": "00da57df13e94e9d98437d13ace4bfe0",
@@ -36,6 +37,9 @@ Object {
     "namespace": Object {
       "type": "keyword",
     },
+    "namespaces": Object {
+      "type": "keyword",
+    },
     "references": Object {
       "properties": Object {
         "id": Object {
diff --git a/src/core/server/saved_objects/routes/integration_tests/import.test.ts b/src/core/server/saved_objects/routes/integration_tests/import.test.ts
index c72d3e241b882..c4a03a0e2e7d2 100644
--- a/src/core/server/saved_objects/routes/integration_tests/import.test.ts
+++ b/src/core/server/saved_objects/routes/integration_tests/import.test.ts
@@ -187,7 +187,7 @@ describe('POST /internal/saved_objects/_import', () => {
           references: [],
           error: {
             statusCode: 409,
-            message: 'version conflict, document already exists',
+            message: 'Saved object [index-pattern/my-pattern] conflict',
           },
         },
         {
diff --git a/src/core/server/saved_objects/saved_objects_service.test.ts b/src/core/server/saved_objects/saved_objects_service.test.ts
index 018117776dcc8..819d79803f371 100644
--- a/src/core/server/saved_objects/saved_objects_service.test.ts
+++ b/src/core/server/saved_objects/saved_objects_service.test.ts
@@ -138,7 +138,7 @@ describe('SavedObjectsService', () => {
         const type = {
           name: 'someType',
           hidden: false,
-          namespaceAgnostic: false,
+          namespaceType: 'single' as 'single',
           mappings: { properties: {} },
         };
         setup.registerType(type);
@@ -251,7 +251,7 @@ describe('SavedObjectsService', () => {
         setup.registerType({
           name: 'someType',
           hidden: false,
-          namespaceAgnostic: false,
+          namespaceType: 'single' as 'single',
           mappings: { properties: {} },
         });
       }).toThrowErrorMatchingInlineSnapshot(
diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts
index 62027928c0bb5..ed4ffef5729ab 100644
--- a/src/core/server/saved_objects/saved_objects_service.ts
+++ b/src/core/server/saved_objects/saved_objects_service.ts
@@ -124,7 +124,7 @@ export interface SavedObjectsServiceSetup {
    * export const myType: SavedObjectsType = {
    *   name: 'MyType',
    *   hidden: false,
-   *   namespaceAgnostic: true,
+   *   namespaceType: 'multiple',
    *   mappings: {
    *     properties: {
    *       textField: {
diff --git a/src/core/server/saved_objects/saved_objects_type_registry.mock.ts b/src/core/server/saved_objects/saved_objects_type_registry.mock.ts
index 8c8458d7a5ce4..8bb66859feca2 100644
--- a/src/core/server/saved_objects/saved_objects_type_registry.mock.ts
+++ b/src/core/server/saved_objects/saved_objects_type_registry.mock.ts
@@ -27,6 +27,8 @@ const createRegistryMock = (): jest.Mocked<ISavedObjectTypeRegistry &
     getAllTypes: jest.fn(),
     getImportableAndExportableTypes: jest.fn(),
     isNamespaceAgnostic: jest.fn(),
+    isSingleNamespace: jest.fn(),
+    isMultiNamespace: jest.fn(),
     isHidden: jest.fn(),
     getIndex: jest.fn(),
     isImportableAndExportable: jest.fn(),
@@ -38,6 +40,10 @@ const createRegistryMock = (): jest.Mocked<ISavedObjectTypeRegistry &
   mock.getIndex.mockReturnValue('.kibana-test');
   mock.isHidden.mockReturnValue(false);
   mock.isNamespaceAgnostic.mockImplementation((type: string) => type === 'global');
+  mock.isSingleNamespace.mockImplementation(
+    (type: string) => type !== 'global' && type !== 'shared'
+  );
+  mock.isMultiNamespace.mockImplementation((type: string) => type === 'shared');
   mock.isImportableAndExportable.mockReturnValue(true);
 
   return mock;
diff --git a/src/core/server/saved_objects/saved_objects_type_registry.test.ts b/src/core/server/saved_objects/saved_objects_type_registry.test.ts
index 4d1d5c1eacc25..84337474f3ee3 100644
--- a/src/core/server/saved_objects/saved_objects_type_registry.test.ts
+++ b/src/core/server/saved_objects/saved_objects_type_registry.test.ts
@@ -23,7 +23,7 @@ import { SavedObjectsType } from './types';
 const createType = (type: Partial<SavedObjectsType>): SavedObjectsType => ({
   name: 'unknown',
   hidden: false,
-  namespaceAgnostic: false,
+  namespaceType: 'single' as 'single',
   mappings: { properties: {} },
   migrations: {},
   ...type,
@@ -164,18 +164,92 @@ describe('SavedObjectTypeRegistry', () => {
   });
 
   describe('#isNamespaceAgnostic', () => {
-    it('returns correct value for the type', () => {
-      registry.registerType(createType({ name: 'typeA', namespaceAgnostic: true }));
-      registry.registerType(createType({ name: 'typeB', namespaceAgnostic: false }));
+    const expectResult = (expected: boolean, schemaDefinition?: Partial<SavedObjectsType>) => {
+      registry = new SavedObjectTypeRegistry();
+      registry.registerType(createType({ name: 'foo', ...schemaDefinition }));
+      expect(registry.isNamespaceAgnostic('foo')).toBe(expected);
+    };
 
-      expect(registry.isNamespaceAgnostic('typeA')).toEqual(true);
-      expect(registry.isNamespaceAgnostic('typeB')).toEqual(false);
+    it(`returns false when the type is not registered`, () => {
+      expect(registry.isNamespaceAgnostic('unknownType')).toEqual(false);
     });
-    it('returns false when the type is not registered', () => {
-      registry.registerType(createType({ name: 'typeA', namespaceAgnostic: true }));
-      registry.registerType(createType({ name: 'typeB', namespaceAgnostic: false }));
 
-      expect(registry.isNamespaceAgnostic('unknownType')).toEqual(false);
+    it(`returns true for namespaceType 'agnostic'`, () => {
+      expectResult(true, { namespaceType: 'agnostic' });
+    });
+
+    it(`returns false for other namespaceType`, () => {
+      expectResult(false, { namespaceType: 'multiple' });
+      expectResult(false, { namespaceType: 'single' });
+      expectResult(false, { namespaceType: undefined });
+    });
+
+    // deprecated test cases
+    it(`returns true when namespaceAgnostic is true`, () => {
+      expectResult(true, { namespaceAgnostic: true, namespaceType: 'agnostic' });
+      expectResult(true, { namespaceAgnostic: true, namespaceType: 'multiple' });
+      expectResult(true, { namespaceAgnostic: true, namespaceType: 'single' });
+      expectResult(true, { namespaceAgnostic: true, namespaceType: undefined });
+    });
+  });
+
+  describe('#isSingleNamespace', () => {
+    const expectResult = (expected: boolean, schemaDefinition?: Partial<SavedObjectsType>) => {
+      registry = new SavedObjectTypeRegistry();
+      registry.registerType(createType({ name: 'foo', ...schemaDefinition }));
+      expect(registry.isSingleNamespace('foo')).toBe(expected);
+    };
+
+    it(`returns true when the type is not registered`, () => {
+      expect(registry.isSingleNamespace('unknownType')).toEqual(true);
+    });
+
+    it(`returns true for namespaceType 'single'`, () => {
+      expectResult(true, { namespaceType: 'single' });
+      expectResult(true, { namespaceType: undefined });
+    });
+
+    it(`returns false for other namespaceType`, () => {
+      expectResult(false, { namespaceType: 'agnostic' });
+      expectResult(false, { namespaceType: 'multiple' });
+    });
+
+    // deprecated test cases
+    it(`returns false when namespaceAgnostic is true`, () => {
+      expectResult(false, { namespaceAgnostic: true, namespaceType: 'agnostic' });
+      expectResult(false, { namespaceAgnostic: true, namespaceType: 'multiple' });
+      expectResult(false, { namespaceAgnostic: true, namespaceType: 'single' });
+      expectResult(false, { namespaceAgnostic: true, namespaceType: undefined });
+    });
+  });
+
+  describe('#isMultiNamespace', () => {
+    const expectResult = (expected: boolean, schemaDefinition?: Partial<SavedObjectsType>) => {
+      registry = new SavedObjectTypeRegistry();
+      registry.registerType(createType({ name: 'foo', ...schemaDefinition }));
+      expect(registry.isMultiNamespace('foo')).toBe(expected);
+    };
+
+    it(`returns false when the type is not registered`, () => {
+      expect(registry.isMultiNamespace('unknownType')).toEqual(false);
+    });
+
+    it(`returns true for namespaceType 'multiple'`, () => {
+      expectResult(true, { namespaceType: 'multiple' });
+    });
+
+    it(`returns false for other namespaceType`, () => {
+      expectResult(false, { namespaceType: 'agnostic' });
+      expectResult(false, { namespaceType: 'single' });
+      expectResult(false, { namespaceType: undefined });
+    });
+
+    // deprecated test cases
+    it(`returns false when namespaceAgnostic is true`, () => {
+      expectResult(false, { namespaceAgnostic: true, namespaceType: 'agnostic' });
+      expectResult(false, { namespaceAgnostic: true, namespaceType: 'multiple' });
+      expectResult(false, { namespaceAgnostic: true, namespaceType: 'single' });
+      expectResult(false, { namespaceAgnostic: true, namespaceType: undefined });
     });
   });
 
@@ -206,8 +280,8 @@ describe('SavedObjectTypeRegistry', () => {
       expect(registry.getIndex('typeWithNoIndex')).toBeUndefined();
     });
     it('returns undefined when the type is not registered', () => {
-      registry.registerType(createType({ name: 'typeA', namespaceAgnostic: true }));
-      registry.registerType(createType({ name: 'typeB', namespaceAgnostic: false }));
+      registry.registerType(createType({ name: 'typeA', namespaceType: 'agnostic' }));
+      registry.registerType(createType({ name: 'typeB', namespaceType: 'single' }));
 
       expect(registry.getIndex('unknownType')).toBeUndefined();
     });
diff --git a/src/core/server/saved_objects/saved_objects_type_registry.ts b/src/core/server/saved_objects/saved_objects_type_registry.ts
index 5580ce3815d0d..be3fdb86a994c 100644
--- a/src/core/server/saved_objects/saved_objects_type_registry.ts
+++ b/src/core/server/saved_objects/saved_objects_type_registry.ts
@@ -25,16 +25,7 @@ import { SavedObjectsType } from './types';
  *
  * @public
  */
-export type ISavedObjectTypeRegistry = Pick<
-  SavedObjectTypeRegistry,
-  | 'getType'
-  | 'getAllTypes'
-  | 'getIndex'
-  | 'isNamespaceAgnostic'
-  | 'isHidden'
-  | 'getImportableAndExportableTypes'
-  | 'isImportableAndExportable'
->;
+export type ISavedObjectTypeRegistry = Omit<SavedObjectTypeRegistry, 'registerType'>;
 
 /**
  * Registry holding information about all the registered {@link SavedObjectsType | saved object types}.
@@ -77,11 +68,31 @@ export class SavedObjectTypeRegistry {
   }
 
   /**
-   * Returns the `namespaceAgnostic` property for given type, or `false` if
-   * the type is not registered.
+   * Returns whether the type is namespace-agnostic (global);
+   * resolves to `false` if the type is not registered
    */
   public isNamespaceAgnostic(type: string) {
-    return this.types.get(type)?.namespaceAgnostic ?? false;
+    return (
+      this.types.get(type)?.namespaceType === 'agnostic' ||
+      this.types.get(type)?.namespaceAgnostic ||
+      false
+    );
+  }
+
+  /**
+   * Returns whether the type is single-namespace (isolated);
+   * resolves to `true` if the type is not registered
+   */
+  public isSingleNamespace(type: string) {
+    return !this.isNamespaceAgnostic(type) && !this.isMultiNamespace(type);
+  }
+
+  /**
+   * Returns whether the type is multi-namespace (shareable);
+   * resolves to `false` if the type is not registered
+   */
+  public isMultiNamespace(type: string) {
+    return !this.isNamespaceAgnostic(type) && this.types.get(type)?.namespaceType === 'multiple';
   }
 
   /**
diff --git a/src/core/server/saved_objects/schema/schema.test.ts b/src/core/server/saved_objects/schema/schema.test.ts
index 43cf27fbae790..f2daa13e43fce 100644
--- a/src/core/server/saved_objects/schema/schema.test.ts
+++ b/src/core/server/saved_objects/schema/schema.test.ts
@@ -17,32 +17,90 @@
  * under the License.
  */
 
-import { SavedObjectsSchema } from './schema';
+import { SavedObjectsSchema, SavedObjectsSchemaDefinition } from './schema';
 
 describe('#isNamespaceAgnostic', () => {
+  const expectResult = (expected: boolean, schemaDefinition?: SavedObjectsSchemaDefinition) => {
+    const schema = new SavedObjectsSchema(schemaDefinition);
+    const result = schema.isNamespaceAgnostic('foo');
+    expect(result).toBe(expected);
+  };
+
+  it(`returns false when no schema is defined`, () => {
+    expectResult(false);
+  });
+
   it(`returns false for unknown types`, () => {
-    const schema = new SavedObjectsSchema();
-    const result = schema.isNamespaceAgnostic('bar');
-    expect(result).toBe(false);
+    expectResult(false, { bar: {} });
   });
 
-  it(`returns true for explicitly namespace agnostic type`, () => {
-    const schema = new SavedObjectsSchema({
-      foo: {
-        isNamespaceAgnostic: true,
-      },
-    });
-    const result = schema.isNamespaceAgnostic('foo');
-    expect(result).toBe(true);
+  it(`returns false for non-namespace-agnostic type`, () => {
+    expectResult(false, { foo: { isNamespaceAgnostic: false } });
+    expectResult(false, { foo: { isNamespaceAgnostic: undefined } });
   });
 
-  it(`returns false for explicitly namespaced type`, () => {
-    const schema = new SavedObjectsSchema({
-      foo: {
-        isNamespaceAgnostic: false,
-      },
-    });
-    const result = schema.isNamespaceAgnostic('foo');
-    expect(result).toBe(false);
+  it(`returns true for explicitly namespace-agnostic type`, () => {
+    expectResult(true, { foo: { isNamespaceAgnostic: true } });
+  });
+});
+
+describe('#isSingleNamespace', () => {
+  const expectResult = (expected: boolean, schemaDefinition?: SavedObjectsSchemaDefinition) => {
+    const schema = new SavedObjectsSchema(schemaDefinition);
+    const result = schema.isSingleNamespace('foo');
+    expect(result).toBe(expected);
+  };
+
+  it(`returns true when no schema is defined`, () => {
+    expectResult(true);
+  });
+
+  it(`returns true for unknown types`, () => {
+    expectResult(true, { bar: {} });
+  });
+
+  it(`returns false for explicitly namespace-agnostic type`, () => {
+    expectResult(false, { foo: { isNamespaceAgnostic: true } });
+  });
+
+  it(`returns false for explicitly multi-namespace type`, () => {
+    expectResult(false, { foo: { multiNamespace: true } });
+  });
+
+  it(`returns true for non-namespace-agnostic and non-multi-namespace type`, () => {
+    expectResult(true, { foo: { isNamespaceAgnostic: false, multiNamespace: false } });
+    expectResult(true, { foo: { isNamespaceAgnostic: false, multiNamespace: undefined } });
+    expectResult(true, { foo: { isNamespaceAgnostic: undefined, multiNamespace: false } });
+    expectResult(true, { foo: { isNamespaceAgnostic: undefined, multiNamespace: undefined } });
+  });
+});
+
+describe('#isMultiNamespace', () => {
+  const expectResult = (expected: boolean, schemaDefinition?: SavedObjectsSchemaDefinition) => {
+    const schema = new SavedObjectsSchema(schemaDefinition);
+    const result = schema.isMultiNamespace('foo');
+    expect(result).toBe(expected);
+  };
+
+  it(`returns false when no schema is defined`, () => {
+    expectResult(false);
+  });
+
+  it(`returns false for unknown types`, () => {
+    expectResult(false, { bar: {} });
+  });
+
+  it(`returns false for explicitly namespace-agnostic type`, () => {
+    expectResult(false, { foo: { isNamespaceAgnostic: true } });
+  });
+
+  it(`returns false for non-multi-namespace type`, () => {
+    expectResult(false, { foo: { multiNamespace: false } });
+    expectResult(false, { foo: { multiNamespace: undefined } });
+  });
+
+  it(`returns true for non-namespace-agnostic and explicitly multi-namespace type`, () => {
+    expectResult(true, { foo: { isNamespaceAgnostic: false, multiNamespace: true } });
+    expectResult(true, { foo: { isNamespaceAgnostic: undefined, multiNamespace: true } });
   });
 });
diff --git a/src/core/server/saved_objects/schema/schema.ts b/src/core/server/saved_objects/schema/schema.ts
index 17ca406ea109a..ba1905158e822 100644
--- a/src/core/server/saved_objects/schema/schema.ts
+++ b/src/core/server/saved_objects/schema/schema.ts
@@ -24,7 +24,8 @@ import { LegacyConfig } from '../../legacy';
  * @internal
  **/
 interface SavedObjectsSchemaTypeDefinition {
-  isNamespaceAgnostic: boolean;
+  isNamespaceAgnostic?: boolean;
+  multiNamespace?: boolean;
   hidden?: boolean;
   indexPattern?: ((config: LegacyConfig) => string) | string;
   convertToAliasScript?: string;
@@ -72,7 +73,7 @@ export class SavedObjectsSchema {
   }
 
   public isNamespaceAgnostic(type: string) {
-    // if no plugins have registered a uiExports.savedObjectSchemas,
+    // if no plugins have registered a Saved Objects Schema,
     // this.schema will be undefined, and no types are namespace agnostic
     if (!this.definition) {
       return false;
@@ -84,4 +85,32 @@ export class SavedObjectsSchema {
     }
     return Boolean(typeSchema.isNamespaceAgnostic);
   }
+
+  public isSingleNamespace(type: string) {
+    // if no plugins have registered a Saved Objects Schema,
+    // this.schema will be undefined, and all types are namespace isolated
+    if (!this.definition) {
+      return true;
+    }
+
+    const typeSchema = this.definition[type];
+    if (!typeSchema) {
+      return true;
+    }
+    return !Boolean(typeSchema.isNamespaceAgnostic) && !Boolean(typeSchema.multiNamespace);
+  }
+
+  public isMultiNamespace(type: string) {
+    // if no plugins have registered a Saved Objects Schema,
+    // this.schema will be undefined, and no types are multi-namespace
+    if (!this.definition) {
+      return false;
+    }
+
+    const typeSchema = this.definition[type];
+    if (!typeSchema) {
+      return false;
+    }
+    return !Boolean(typeSchema.isNamespaceAgnostic) && Boolean(typeSchema.multiNamespace);
+  }
 }
diff --git a/src/core/server/saved_objects/serialization/serializer.test.ts b/src/core/server/saved_objects/serialization/serializer.test.ts
index 8f09b25bb3908..1a7dfdd2d130e 100644
--- a/src/core/server/saved_objects/serialization/serializer.test.ts
+++ b/src/core/server/saved_objects/serialization/serializer.test.ts
@@ -19,101 +19,101 @@
 
 import _ from 'lodash';
 import { SavedObjectsSerializer } from './serializer';
+import { SavedObjectsRawDoc } from './types';
 import { typeRegistryMock } from '../saved_objects_type_registry.mock';
 import { encodeVersion } from '../version';
 
-describe('saved object conversion', () => {
-  let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
-
-  beforeEach(() => {
-    typeRegistry = typeRegistryMock.create();
-    typeRegistry.isNamespaceAgnostic.mockReturnValue(false);
+let typeRegistry = typeRegistryMock.create();
+typeRegistry.isNamespaceAgnostic.mockReturnValue(true);
+typeRegistry.isSingleNamespace.mockReturnValue(false);
+typeRegistry.isMultiNamespace.mockReturnValue(false);
+const namespaceAgnosticSerializer = new SavedObjectsSerializer(typeRegistry);
+
+typeRegistry = typeRegistryMock.create();
+typeRegistry.isNamespaceAgnostic.mockReturnValue(false);
+typeRegistry.isSingleNamespace.mockReturnValue(true);
+typeRegistry.isMultiNamespace.mockReturnValue(false);
+const singleNamespaceSerializer = new SavedObjectsSerializer(typeRegistry);
+
+typeRegistry = typeRegistryMock.create();
+typeRegistry.isNamespaceAgnostic.mockReturnValue(false);
+typeRegistry.isSingleNamespace.mockReturnValue(false);
+typeRegistry.isMultiNamespace.mockReturnValue(true);
+const multiNamespaceSerializer = new SavedObjectsSerializer(typeRegistry);
+
+const sampleTemplate = {
+  _id: 'foo:bar',
+  _source: {
+    type: 'foo',
+  },
+};
+const createSampleDoc = (raw: any, template = sampleTemplate): SavedObjectsRawDoc =>
+  _.defaultsDeep(raw, template);
+
+describe('#rawToSavedObject', () => {
+  test('it copies the _source.type property to type', () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+      },
+    });
+    expect(actual).toHaveProperty('type', 'foo');
   });
 
-  describe('#rawToSavedObject', () => {
-    test('it copies the _source.type property to type', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'foo:bar',
-        _source: {
-          type: 'foo',
-        },
-      });
-      expect(actual).toHaveProperty('type', 'foo');
+  test('it copies the _source.references property to references', () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+        references: [{ name: 'ref_0', type: 'index-pattern', id: 'pattern*' }],
+      },
     });
+    expect(actual).toHaveProperty('references', [
+      {
+        name: 'ref_0',
+        type: 'index-pattern',
+        id: 'pattern*',
+      },
+    ]);
+  });
 
-    test('it copies the _source.references property to references', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'foo:bar',
-        _source: {
-          type: 'foo',
-          references: [{ name: 'ref_0', type: 'index-pattern', id: 'pattern*' }],
-        },
-      });
-      expect(actual).toHaveProperty('references', [
-        {
-          name: 'ref_0',
-          type: 'index-pattern',
-          id: 'pattern*',
+  test('if specified it copies the _source.migrationVersion property to migrationVersion', () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+        migrationVersion: {
+          hello: '1.2.3',
+          acl: '33.3.5',
         },
-      ]);
+      },
     });
-
-    test('if specified it copies the _source.migrationVersion property to migrationVersion', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'foo:bar',
-        _source: {
-          type: 'foo',
-          migrationVersion: {
-            hello: '1.2.3',
-            acl: '33.3.5',
-          },
-        },
-      });
-      expect(actual).toHaveProperty('migrationVersion', {
-        hello: '1.2.3',
-        acl: '33.3.5',
-      });
+    expect(actual).toHaveProperty('migrationVersion', {
+      hello: '1.2.3',
+      acl: '33.3.5',
     });
+  });
 
-    test(`if _source.migrationVersion is unspecified it doesn't set migrationVersion`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'foo:bar',
-        _source: {
-          type: 'foo',
-        },
-      });
-      expect(actual).not.toHaveProperty('migrationVersion');
+  test(`if _source.migrationVersion is unspecified it doesn't set migrationVersion`, () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+      },
     });
+    expect(actual).not.toHaveProperty('migrationVersion');
+  });
 
-    test('it converts the id and type properties, and retains migrationVersion', () => {
-      const now = String(new Date());
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'hello:world',
-        _seq_no: 3,
-        _primary_term: 1,
-        _source: {
-          type: 'hello',
-          hello: {
-            a: 'b',
-            c: 'd',
-          },
-          migrationVersion: {
-            hello: '1.2.3',
-            acl: '33.3.5',
-          },
-          updated_at: now,
-        },
-      });
-      const expected = {
-        id: 'world',
+  test('it converts the id and type properties, and retains migrationVersion', () => {
+    const now = String(new Date());
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'hello:world',
+      _seq_no: 3,
+      _primary_term: 1,
+      _source: {
         type: 'hello',
-        version: encodeVersion(3, 1),
-        attributes: {
+        hello: {
           a: 'b',
           c: 'd',
         },
@@ -122,909 +122,937 @@ describe('saved object conversion', () => {
           acl: '33.3.5',
         },
         updated_at: now,
-        references: [],
-      };
-      expect(expected).toEqual(actual);
+      },
+    });
+    const expected = {
+      id: 'world',
+      type: 'hello',
+      version: encodeVersion(3, 1),
+      attributes: {
+        a: 'b',
+        c: 'd',
+      },
+      migrationVersion: {
+        hello: '1.2.3',
+        acl: '33.3.5',
+      },
+      updated_at: now,
+      references: [],
+    };
+    expect(expected).toEqual(actual);
+  });
+
+  test(`if version is unspecified it doesn't set version`, () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+        hello: {},
+      },
     });
+    expect(actual).not.toHaveProperty('version');
+  });
 
-    test(`if version is unspecified it doesn't set version`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
+  test(`if specified it encodes _seq_no and _primary_term to version`, () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _seq_no: 4,
+      _primary_term: 1,
+      _source: {
+        type: 'foo',
+        hello: {},
+      },
+    });
+    expect(actual).toHaveProperty('version', encodeVersion(4, 1));
+  });
+
+  test(`if only _seq_no is specified it throws`, () => {
+    expect(() =>
+      singleNamespaceSerializer.rawToSavedObject({
         _id: 'foo:bar',
+        _seq_no: 4,
         _source: {
           type: 'foo',
           hello: {},
         },
-      });
-      expect(actual).not.toHaveProperty('version');
-    });
+      })
+    ).toThrowErrorMatchingInlineSnapshot(`"_primary_term from elasticsearch must be an integer"`);
+  });
 
-    test(`if specified it encodes _seq_no and _primary_term to version`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
+  test(`if only _primary_term is throws`, () => {
+    expect(() =>
+      singleNamespaceSerializer.rawToSavedObject({
         _id: 'foo:bar',
-        _seq_no: 4,
         _primary_term: 1,
         _source: {
           type: 'foo',
           hello: {},
         },
-      });
-      expect(actual).toHaveProperty('version', encodeVersion(4, 1));
-    });
+      })
+    ).toThrowErrorMatchingInlineSnapshot(`"_seq_no from elasticsearch must be an integer"`);
+  });
 
-    test(`if only _seq_no is specified it throws`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      expect(() =>
-        serializer.rawToSavedObject({
-          _id: 'foo:bar',
-          _seq_no: 4,
-          _source: {
-            type: 'foo',
-            hello: {},
-          },
-        })
-      ).toThrowErrorMatchingInlineSnapshot(`"_primary_term from elasticsearch must be an integer"`);
+  test('if specified it copies the _source.updated_at property to updated_at', () => {
+    const now = Date();
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+        updated_at: now,
+      },
     });
+    expect(actual).toHaveProperty('updated_at', now);
+  });
 
-    test(`if only _primary_term is throws`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      expect(() =>
-        serializer.rawToSavedObject({
-          _id: 'foo:bar',
-          _primary_term: 1,
-          _source: {
-            type: 'foo',
-            hello: {},
-          },
-        })
-      ).toThrowErrorMatchingInlineSnapshot(`"_seq_no from elasticsearch must be an integer"`);
+  test(`if _source.updated_at is unspecified it doesn't set updated_at`, () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'foo:bar',
+      _source: {
+        type: 'foo',
+      },
     });
+    expect(actual).not.toHaveProperty('updated_at');
+  });
 
-    test('if specified it copies the _source.updated_at property to updated_at', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const now = Date();
-      const actual = serializer.rawToSavedObject({
-        _id: 'foo:bar',
-        _source: {
-          type: 'foo',
-          updated_at: now,
+  test('it does not pass unknown properties through', () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'universe',
+      _source: {
+        type: 'hello',
+        hello: {
+          world: 'earth',
         },
-      });
-      expect(actual).toHaveProperty('updated_at', now);
+        banjo: 'Steve Martin',
+      },
+    });
+    expect(actual).toEqual({
+      id: 'universe',
+      type: 'hello',
+      attributes: {
+        world: 'earth',
+      },
+      references: [],
     });
+  });
 
-    test(`if _source.updated_at is unspecified it doesn't set updated_at`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'foo:bar',
-        _source: {
-          type: 'foo',
-        },
-      });
-      expect(actual).not.toHaveProperty('updated_at');
+  test('it does not create attributes if [type] is missing', () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'universe',
+      _source: {
+        type: 'hello',
+      },
     });
+    expect(actual).toEqual({
+      id: 'universe',
+      type: 'hello',
+      references: [],
+    });
+  });
 
-    test('it does not pass unknown properties through', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
+  test('it fails for documents which do not specify a type', () => {
+    expect(() =>
+      singleNamespaceSerializer.rawToSavedObject({
         _id: 'universe',
         _source: {
-          type: 'hello',
           hello: {
             world: 'earth',
           },
-          banjo: 'Steve Martin',
+        } as any,
+      })
+    ).toThrow(/Expected "undefined" to be a saved object type/);
+  });
+
+  test('it is complimentary with savedObjectToRaw', () => {
+    const raw = {
+      _id: 'foo-namespace:foo:bar',
+      _primary_term: 24,
+      _seq_no: 42,
+      _source: {
+        type: 'foo',
+        foo: {
+          meaning: 42,
+          nested: { stuff: 'here' },
         },
-      });
-      expect(actual).toEqual({
-        id: 'universe',
-        type: 'hello',
-        attributes: {
-          world: 'earth',
+        migrationVersion: {
+          foo: '1.2.3',
+          bar: '9.8.7',
         },
+        namespace: 'foo-namespace',
+        updated_at: String(new Date()),
         references: [],
-      });
-    });
+      },
+    };
+
+    expect(
+      singleNamespaceSerializer.savedObjectToRaw(
+        singleNamespaceSerializer.rawToSavedObject(_.cloneDeep(raw))
+      )
+    ).toEqual(raw);
+  });
 
-    test('it does not create attributes if [type] is missing', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'universe',
-        _source: {
-          type: 'hello',
-        },
-      });
-      expect(actual).toEqual({
-        id: 'universe',
+  test('it handles unprefixed ids', () => {
+    const actual = singleNamespaceSerializer.rawToSavedObject({
+      _id: 'universe',
+      _source: {
         type: 'hello',
-        references: [],
-      });
+      },
     });
 
-    test('it fails for documents which do not specify a type', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      expect(() =>
-        serializer.rawToSavedObject({
-          _id: 'universe',
-          _source: {
-            hello: {
-              world: 'earth',
-            },
-          } as any,
-        })
-      ).toThrow(/Expected "undefined" to be a saved object type/);
+    expect(actual).toHaveProperty('id', 'universe');
+  });
+
+  describe('namespace-agnostic type with a namespace', () => {
+    const raw = createSampleDoc({ _source: { namespace: 'baz' } });
+    const actual = namespaceAgnosticSerializer.rawToSavedObject(raw);
+
+    test(`removes type prefix from _id`, () => {
+      expect(actual).toHaveProperty('id', 'bar');
     });
 
-    test('it is complimentary with savedObjectToRaw', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const raw = {
-        _id: 'foo-namespace:foo:bar',
-        _primary_term: 24,
-        _seq_no: 42,
-        _source: {
-          type: 'foo',
-          foo: {
-            meaning: 42,
-            nested: { stuff: 'here' },
-          },
-          migrationVersion: {
-            foo: '1.2.3',
-            bar: '9.8.7',
-          },
-          namespace: 'foo-namespace',
-          updated_at: String(new Date()),
-          references: [],
-        },
-      };
+    test(`copies _id to id if prefixed by namespace and type`, () => {
+      const _id = `${raw._source.namespace}:${raw._id}`;
+      const _actual = namespaceAgnosticSerializer.rawToSavedObject({ ...raw, _id });
+      expect(_actual).toHaveProperty('id', _id);
+    });
 
-      expect(serializer.savedObjectToRaw(serializer.rawToSavedObject(_.cloneDeep(raw)))).toEqual(
-        raw
-      );
+    test(`doesn't copy _source.namespace to namespace`, () => {
+      expect(actual).not.toHaveProperty('namespace');
     });
+  });
 
-    test('it handles unprefixed ids', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.rawToSavedObject({
-        _id: 'universe',
-        _source: {
-          type: 'hello',
-        },
-      });
+  describe('namespace-agnostic type with namespaces', () => {
+    const raw = createSampleDoc({ _source: { namespaces: ['baz'] } });
+    const actual = namespaceAgnosticSerializer.rawToSavedObject(raw);
 
-      expect(actual).toHaveProperty('id', 'universe');
+    test(`doesn't copy _source.namespaces to namespaces`, () => {
+      expect(actual).not.toHaveProperty('namespaces');
     });
+  });
 
-    describe('namespaced type without a namespace', () => {
-      test(`removes type prefix from _id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'foo:bar',
-          _source: {
-            type: 'foo',
-          },
-        });
+  describe('single-namespace type without a namespace', () => {
+    const raw = createSampleDoc({});
+    const actual = singleNamespaceSerializer.rawToSavedObject(raw);
 
-        expect(actual).toHaveProperty('id', 'bar');
-      });
+    test(`removes type prefix from _id`, () => {
+      expect(actual).toHaveProperty('id', 'bar');
+    });
 
-      test(`if prefixed by random prefix and type it copies _id to id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'random:foo:bar',
-          _source: {
-            type: 'foo',
-          },
-        });
+    test(`copies _id to id if prefixed by random prefix and type`, () => {
+      const _id = `random:${raw._id}`;
+      const _actual = singleNamespaceSerializer.rawToSavedObject({ ...raw, _id });
+      expect(_actual).toHaveProperty('id', _id);
+    });
 
-        expect(actual).toHaveProperty('id', 'random:foo:bar');
-      });
+    test(`doesn't specify namespace`, () => {
+      expect(actual).not.toHaveProperty('namespace');
+    });
+  });
 
-      test(`doesn't specify namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'foo:bar',
-          _source: {
-            type: 'foo',
-          },
-        });
+  describe('single-namespace type with a namespace', () => {
+    const namespace = 'baz';
+    const raw = createSampleDoc({ _source: { namespace } });
+    const actual = singleNamespaceSerializer.rawToSavedObject(raw);
 
-        expect(actual).not.toHaveProperty('namespace');
-      });
+    test(`removes type and namespace prefix from _id`, () => {
+      const _id = `${namespace}:${raw._id}`;
+      const _actual = singleNamespaceSerializer.rawToSavedObject({ ...raw, _id });
+      expect(_actual).toHaveProperty('id', 'bar');
     });
 
-    describe('namespaced type with a namespace', () => {
-      test(`removes type and namespace prefix from _id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'baz:foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+    test(`copies _id to id if prefixed only by type`, () => {
+      expect(actual).toHaveProperty('id', raw._id);
+    });
 
-        expect(actual).toHaveProperty('id', 'bar');
-      });
+    test(`copies _id to id if prefixed by random prefix and type`, () => {
+      const _id = `random:${raw._id}`;
+      const _actual = singleNamespaceSerializer.rawToSavedObject({ ...raw, _id });
+      expect(_actual).toHaveProperty('id', _id);
+    });
 
-      test(`if prefixed by only type it copies _id to id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+    test(`copies _source.namespace to namespace`, () => {
+      expect(actual).toHaveProperty('namespace', 'baz');
+    });
+  });
 
-        expect(actual).toHaveProperty('id', 'foo:bar');
-      });
+  describe('single-namespace type with namespaces', () => {
+    const raw = createSampleDoc({ _source: { namespaces: ['baz'] } });
+    const actual = singleNamespaceSerializer.rawToSavedObject(raw);
 
-      test(`if prefixed by random prefix and type it copies _id to id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'random:foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+    test(`doesn't copy _source.namespaces to namespaces`, () => {
+      expect(actual).not.toHaveProperty('namespaces');
+    });
+  });
 
-        expect(actual).toHaveProperty('id', 'random:foo:bar');
-      });
+  describe('multi-namespace type with a namespace', () => {
+    const raw = createSampleDoc({ _source: { namespace: 'baz' } });
+    const actual = multiNamespaceSerializer.rawToSavedObject(raw);
 
-      test(`copies _source.namespace to namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'baz:foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+    test(`removes type prefix from _id`, () => {
+      expect(actual).toHaveProperty('id', 'bar');
+    });
 
-        expect(actual).toHaveProperty('namespace', 'baz');
-      });
+    test(`copies _id to id if prefixed by namespace and type`, () => {
+      const _id = `${raw._source.namespace}:${raw._id}`;
+      const _actual = multiNamespaceSerializer.rawToSavedObject({ ...raw, _id });
+      expect(_actual).toHaveProperty('id', _id);
     });
 
-    describe('namespace agnostic type with a namespace', () => {
-      beforeEach(() => {
-        typeRegistry.isNamespaceAgnostic.mockReturnValue(true);
-      });
+    test(`doesn't copy _source.namespace to namespace`, () => {
+      expect(actual).not.toHaveProperty('namespace');
+    });
+  });
 
-      test(`removes type prefix from _id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+  describe('multi-namespace type with namespaces', () => {
+    const raw = createSampleDoc({ _source: { namespaces: ['baz'] } });
+    const actual = multiNamespaceSerializer.rawToSavedObject(raw);
 
-        expect(actual).toHaveProperty('id', 'bar');
-      });
+    test(`copies _source.namespaces to namespaces`, () => {
+      expect(actual).toHaveProperty('namespaces', ['baz']);
+    });
+  });
+});
 
-      test(`if prefixed by namespace and type it copies _id to id`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'baz:foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+describe('#savedObjectToRaw', () => {
+  test('it copies the type property to _source.type and uses the ROOT_TYPE as _type', () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: 'foo',
+      attributes: {},
+    } as any);
 
-        expect(actual).toHaveProperty('id', 'baz:foo:bar');
-      });
+    expect(actual._source).toHaveProperty('type', 'foo');
+  });
 
-      test(`doesn't copy _source.namespace to namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.rawToSavedObject({
-          _id: 'baz:foo:bar',
-          _source: {
-            type: 'foo',
-            namespace: 'baz',
-          },
-        });
+  test('it copies the references property to _source.references', () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      id: '1',
+      type: 'foo',
+      attributes: {},
+      references: [{ name: 'ref_0', type: 'index-pattern', id: 'pattern*' }],
+    });
+    expect(actual._source).toHaveProperty('references', [
+      {
+        name: 'ref_0',
+        type: 'index-pattern',
+        id: 'pattern*',
+      },
+    ]);
+  });
+
+  test('if specified it copies the updated_at property to _source.updated_at', () => {
+    const now = new Date();
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: '',
+      attributes: {},
+      updated_at: now,
+    } as any);
+
+    expect(actual._source).toHaveProperty('updated_at', now);
+  });
+
+  test(`if unspecified it doesn't add updated_at property to _source`, () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: '',
+      attributes: {},
+    } as any);
 
-        expect(actual).not.toHaveProperty('namespace');
-      });
+    expect(actual._source).not.toHaveProperty('updated_at');
+  });
+
+  test('it copies the migrationVersion property to _source.migrationVersion', () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: '',
+      attributes: {},
+      migrationVersion: {
+        foo: '1.2.3',
+        bar: '9.8.7',
+      },
+    } as any);
+
+    expect(actual._source).toHaveProperty('migrationVersion', {
+      foo: '1.2.3',
+      bar: '9.8.7',
     });
   });
 
-  describe('#savedObjectToRaw', () => {
-    test('it copies the type property to _source.type and uses the ROOT_TYPE as _type', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        type: 'foo',
+  test(`if unspecified it doesn't add migrationVersion property to _source`, () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: '',
+      attributes: {},
+    } as any);
+
+    expect(actual._source).not.toHaveProperty('migrationVersion');
+  });
+
+  test('it decodes the version property to _seq_no and _primary_term', () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: '',
+      attributes: {},
+      version: encodeVersion(1, 2),
+    } as any);
+
+    expect(actual).toHaveProperty('_seq_no', 1);
+    expect(actual).toHaveProperty('_primary_term', 2);
+  });
+
+  test(`if unspecified it doesn't add _seq_no or _primary_term properties`, () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: '',
+      attributes: {},
+    } as any);
+
+    expect(actual).not.toHaveProperty('_seq_no');
+    expect(actual).not.toHaveProperty('_primary_term');
+  });
+
+  test(`if version invalid it throws`, () => {
+    expect(() =>
+      singleNamespaceSerializer.savedObjectToRaw({
+        type: '',
         attributes: {},
-      } as any);
+        version: 'foo',
+      } as any)
+    ).toThrowErrorMatchingInlineSnapshot(`"Invalid version [foo]"`);
+  });
 
-      expect(actual._source).toHaveProperty('type', 'foo');
+  test('it copies attributes to _source[type]', () => {
+    const actual = singleNamespaceSerializer.savedObjectToRaw({
+      type: 'foo',
+      attributes: {
+        foo: true,
+        bar: 'quz',
+      },
+    } as any);
+
+    expect(actual._source).toHaveProperty('foo', {
+      foo: true,
+      bar: 'quz',
     });
+  });
 
-    test('it copies the references property to _source.references', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        id: '1',
+  describe('single-namespace type without a namespace', () => {
+    test('generates an id prefixed with type, if no id is specified', () => {
+      const v1 = singleNamespaceSerializer.savedObjectToRaw({
         type: 'foo',
-        attributes: {},
-        references: [{ name: 'ref_0', type: 'index-pattern', id: 'pattern*' }],
-      });
-      expect(actual._source).toHaveProperty('references', [
-        {
-          name: 'ref_0',
-          type: 'index-pattern',
-          id: 'pattern*',
-        },
-      ]);
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = singleNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        attributes: { bar: true },
+      } as any);
+
+      expect(v1._id).toMatch(/^foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
     });
 
-    test('if specified it copies the updated_at property to _source.updated_at', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const now = new Date();
-      const actual = serializer.savedObjectToRaw({
+    test(`doesn't specify _source.namespace`, () => {
+      const actual = singleNamespaceSerializer.savedObjectToRaw({
         type: '',
         attributes: {},
-        updated_at: now,
       } as any);
 
-      expect(actual._source).toHaveProperty('updated_at', now);
+      expect(actual._source).not.toHaveProperty('namespace');
     });
+  });
 
-    test(`if unspecified it doesn't add updated_at property to _source`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        type: '',
+  describe('single-namespace type with a namespace', () => {
+    test('generates an id prefixed with namespace and type, if no id is specified', () => {
+      const v1 = singleNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = singleNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
+        attributes: { bar: true },
+      } as any);
+
+      expect(v1._id).toMatch(/^bar\:foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
+    });
+
+    test(`it copies namespace to _source.namespace`, () => {
+      const actual = singleNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
         attributes: {},
+        namespace: 'bar',
       } as any);
 
-      expect(actual._source).not.toHaveProperty('updated_at');
+      expect(actual._source).toHaveProperty('namespace', 'bar');
     });
+  });
 
-    test('it copies the migrationVersion property to _source.migrationVersion', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        type: '',
+  describe('single-namespace type with namespaces', () => {
+    test('generates an id prefixed with type, if no id is specified', () => {
+      const v1 = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
+        attributes: { bar: true },
+      } as any);
+
+      expect(v1._id).toMatch(/^foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
+    });
+
+    test(`doesn't specify _source.namespaces`, () => {
+      const actual = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
         attributes: {},
-        migrationVersion: {
-          foo: '1.2.3',
-          bar: '9.8.7',
-        },
       } as any);
 
-      expect(actual._source).toHaveProperty('migrationVersion', {
-        foo: '1.2.3',
-        bar: '9.8.7',
-      });
+      expect(actual._source).not.toHaveProperty('namespaces');
     });
+  });
 
-    test(`if unspecified it doesn't add migrationVersion property to _source`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        type: '',
+  describe('namespace-agnostic type with a namespace', () => {
+    test('generates an id prefixed with type, if no id is specified', () => {
+      const v1 = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
+        attributes: { bar: true },
+      } as any);
+
+      expect(v1._id).toMatch(/^foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
+    });
+
+    test(`doesn't specify _source.namespace`, () => {
+      const actual = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
         attributes: {},
       } as any);
 
-      expect(actual._source).not.toHaveProperty('migrationVersion');
+      expect(actual._source).not.toHaveProperty('namespace');
     });
+  });
 
-    test('it decodes the version property to _seq_no and _primary_term', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        type: '',
+  describe('namespace-agnostic type with namespaces', () => {
+    test('generates an id prefixed with type, if no id is specified', () => {
+      const v1 = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
+        attributes: { bar: true },
+      } as any);
+
+      expect(v1._id).toMatch(/^foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
+    });
+
+    test(`doesn't specify _source.namespaces`, () => {
+      const actual = namespaceAgnosticSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
         attributes: {},
-        version: encodeVersion(1, 2),
       } as any);
 
-      expect(actual).toHaveProperty('_seq_no', 1);
-      expect(actual).toHaveProperty('_primary_term', 2);
+      expect(actual._source).not.toHaveProperty('namespaces');
     });
+  });
 
-    test(`if unspecified it doesn't add _seq_no or _primary_term properties`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
-        type: '',
+  describe('multi-namespace type with a namespace', () => {
+    test('generates an id prefixed with type, if no id is specified', () => {
+      const v1 = multiNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = multiNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
+        attributes: { bar: true },
+      } as any);
+
+      expect(v1._id).toMatch(/^foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
+    });
+
+    test(`doesn't specify _source.namespace`, () => {
+      const actual = multiNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespace: 'bar',
         attributes: {},
       } as any);
 
-      expect(actual).not.toHaveProperty('_seq_no');
-      expect(actual).not.toHaveProperty('_primary_term');
+      expect(actual._source).not.toHaveProperty('namespace');
     });
+  });
+
+  describe('multi-namespace type with namespaces', () => {
+    test('generates an id prefixed with type, if no id is specified', () => {
+      const v1 = multiNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
+        attributes: { bar: true },
+      } as any);
+
+      const v2 = multiNamespaceSerializer.savedObjectToRaw({
+        type: 'foo',
+        namespaces: ['bar'],
+        attributes: { bar: true },
+      } as any);
 
-    test(`if version invalid it throws`, () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      expect(() =>
-        serializer.savedObjectToRaw({
-          type: '',
-          attributes: {},
-          version: 'foo',
-        } as any)
-      ).toThrowErrorMatchingInlineSnapshot(`"Invalid version [foo]"`);
+      expect(v1._id).toMatch(/^foo\:[\w-]+$/);
+      expect(v1._id).not.toEqual(v2._id);
     });
 
-    test('it copies attributes to _source[type]', () => {
-      const serializer = new SavedObjectsSerializer(typeRegistry);
-      const actual = serializer.savedObjectToRaw({
+    test(`it copies namespaces to _source.namespaces`, () => {
+      const actual = multiNamespaceSerializer.savedObjectToRaw({
         type: 'foo',
-        attributes: {
-          foo: true,
-          bar: 'quz',
-        },
+        namespaces: ['bar'],
+        attributes: {},
       } as any);
 
-      expect(actual._source).toHaveProperty('foo', {
-        foo: true,
-        bar: 'quz',
-      });
+      expect(actual._source).toHaveProperty('namespaces', ['bar']);
     });
+  });
+});
 
-    describe('namespaced type without a namespace', () => {
-      test('generates an id prefixed with type, if no id is specified', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const v1 = serializer.savedObjectToRaw({
-          type: 'foo',
-          attributes: {
-            bar: true,
+describe('#isRawSavedObject', () => {
+  describe('single-namespace type without a namespace', () => {
+    test('is true if the id is prefixed and the type matches', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'hello',
+            hello: {},
           },
-        } as any);
+        })
+      ).toBeTruthy();
+    });
 
-        const v2 = serializer.savedObjectToRaw({
-          type: 'foo',
-          attributes: {
-            bar: true,
+    test('is false if the id is not prefixed', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'world',
+          _source: {
+            type: 'hello',
+            hello: {},
           },
-        } as any);
+        })
+      ).toBeFalsy();
+    });
 
-        expect(v1._id).toMatch(/foo\:[\w-]+$/);
-        expect(v1._id).not.toEqual(v2._id);
-      });
+    test('is false if the type attribute is missing', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            hello: {},
+          } as any,
+        })
+      ).toBeFalsy();
+    });
 
-      test(`doesn't specify _source.namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.savedObjectToRaw({
-          type: '',
-          attributes: {},
-        } as any);
+    test(`is false if the type prefix omits the :`, () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'helloworld',
+          _source: {
+            type: 'hello',
+            hello: {},
+          },
+        })
+      ).toBeFalsy();
+    });
 
-        expect(actual._source).not.toHaveProperty('namespace');
-      });
+    test('is false if the type attribute does not match the id', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'jam',
+            jam: {},
+            hello: {},
+          },
+        })
+      ).toBeFalsy();
     });
 
-    describe('namespaced type with a namespace', () => {
-      test('generates an id prefixed with namespace and type, if no id is specified', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const v1 = serializer.savedObjectToRaw({
-          type: 'foo',
-          namespace: 'bar',
-          attributes: {
-            bar: true,
+    test('is false if there is no [type] attribute', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'hello',
+            jam: {},
           },
-        } as any);
+        })
+      ).toBeFalsy();
+    });
+  });
 
-        const v2 = serializer.savedObjectToRaw({
-          type: 'foo',
-          namespace: 'bar',
-          attributes: {
-            bar: true,
+  describe('single-namespace type with a namespace', () => {
+    test('is true if the id is prefixed with type and namespace and the type matches', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'foo:hello:world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
           },
-        } as any);
+        })
+      ).toBeTruthy();
+    });
 
-        expect(v1._id).toMatch(/bar\:foo\:[\w-]+$/);
-        expect(v1._id).not.toEqual(v2._id);
-      });
+    test('is false if the id is not prefixed by anything', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
 
-      test(`it copies namespace to _source.namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.savedObjectToRaw({
-          type: 'foo',
-          attributes: {},
-          namespace: 'bar',
-        } as any);
+    test('is false if the id is prefixed only with type and the type matches', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+
+    test('is false if the id is prefixed only with namespace and the namespace matches', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'foo:world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
 
-        expect(actual._source).toHaveProperty('namespace', 'bar');
-      });
+    test(`is false if the id prefix omits the trailing :`, () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'foo:helloworld',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
     });
 
-    describe('namespace agnostic type with a namespace', () => {
-      beforeEach(() => {
-        typeRegistry.isNamespaceAgnostic.mockReturnValue(true);
-      });
+    test('is false if the type attribute is missing', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'foo:hello:world',
+          _source: {
+            hello: {},
+            namespace: 'foo',
+          } as any,
+        })
+      ).toBeFalsy();
+    });
 
-      test('generates an id prefixed with type, if no id is specified', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const v1 = serializer.savedObjectToRaw({
-          type: 'foo',
-          namespace: 'bar',
-          attributes: {
-            bar: true,
+    test('is false if the type attribute does not match the id', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'foo:hello:world',
+          _source: {
+            type: 'jam',
+            jam: {},
+            hello: {},
+            namespace: 'foo',
           },
-        } as any);
+        })
+      ).toBeFalsy();
+    });
 
-        const v2 = serializer.savedObjectToRaw({
-          type: 'foo',
-          namespace: 'bar',
-          attributes: {
-            bar: true,
+    test('is false if the namespace attribute does not match the id', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'bar:jam:world',
+          _source: {
+            type: 'jam',
+            jam: {},
+            hello: {},
+            namespace: 'foo',
           },
-        } as any);
+        })
+      ).toBeFalsy();
+    });
 
-        expect(v1._id).toMatch(/foo\:[\w-]+$/);
-        expect(v1._id).not.toEqual(v2._id);
-      });
+    test('is false if there is no [type] attribute', () => {
+      expect(
+        singleNamespaceSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'hello',
+            jam: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+  });
 
-      test(`doesn't specify _source.namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const actual = serializer.savedObjectToRaw({
-          type: 'foo',
-          namespace: 'bar',
-          attributes: {},
-        } as any);
+  describe('namespace-agnostic type with a namespace', () => {
+    test('is true if the id is prefixed with type and the type matches', () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeTruthy();
+    });
+
+    test('is false if the id is not prefixed', () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+
+    test('is false if the id is prefixed with type and namespace', () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'foo:hello:world',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+
+    test(`is false if the type prefix omits the :`, () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'helloworld',
+          _source: {
+            type: 'hello',
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+
+    test('is false if the type attribute is missing', () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            hello: {},
+            namespace: 'foo',
+          } as any,
+        })
+      ).toBeFalsy();
+    });
+
+    test('is false if the type attribute does not match the id', () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'jam',
+            jam: {},
+            hello: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+
+    test('is false if there is no [type] attribute', () => {
+      expect(
+        namespaceAgnosticSerializer.isRawSavedObject({
+          _id: 'hello:world',
+          _source: {
+            type: 'hello',
+            jam: {},
+            namespace: 'foo',
+          },
+        })
+      ).toBeFalsy();
+    });
+  });
+});
 
-        expect(actual._source).not.toHaveProperty('namespace');
-      });
+describe('#generateRawId', () => {
+  describe('single-namespace type without a namespace', () => {
+    test('generates an id if none is specified', () => {
+      const id = singleNamespaceSerializer.generateRawId('', 'goodbye');
+      expect(id).toMatch(/^goodbye\:[\w-]+$/);
+    });
+
+    test('uses the id that is specified', () => {
+      const id = singleNamespaceSerializer.generateRawId('', 'hello', 'world');
+      expect(id).toEqual('hello:world');
     });
   });
 
-  describe('#isRawSavedObject', () => {
-    describe('namespaced type without a namespace', () => {
-      test('is true if the id is prefixed and the type matches', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'hello',
-              hello: {},
-            },
-          })
-        ).toBeTruthy();
-      });
-
-      test('is false if the id is not prefixed', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'world',
-            _source: {
-              type: 'hello',
-              hello: {},
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the type attribute is missing', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              hello: {},
-            } as any,
-          })
-        ).toBeFalsy();
-      });
-
-      test(`is false if the type prefix omits the :`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'helloworld',
-            _source: {
-              type: 'hello',
-              hello: {},
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the type attribute does not match the id', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'jam',
-              jam: {},
-              hello: {},
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if there is no [type] attribute', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'hello',
-              jam: {},
-            },
-          })
-        ).toBeFalsy();
-      });
-    });
-
-    describe('namespaced type with a namespace', () => {
-      test('is true if the id is prefixed with type and namespace and the type matches', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'foo:hello:world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeTruthy();
-      });
-
-      test('is false if the id is not prefixed by anything', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the id is prefixed only with type and the type matches', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the id is prefixed only with namespace and the namespace matches', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'foo:world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test(`is false if the id prefix omits the trailing :`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'foo:helloworld',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the type attribute is missing', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'foo:hello:world',
-            _source: {
-              hello: {},
-              namespace: 'foo',
-            } as any,
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the type attribute does not match the id', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'foo:hello:world',
-            _source: {
-              type: 'jam',
-              jam: {},
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the namespace attribute does not match the id', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'bar:jam:world',
-            _source: {
-              type: 'jam',
-              jam: {},
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if there is no [type] attribute', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'hello',
-              jam: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-    });
-
-    describe('namespace agnostic type with a namespace', () => {
-      beforeEach(() => {
-        typeRegistry.isNamespaceAgnostic.mockReturnValue(true);
-      });
-
-      test('is true if the id is prefixed with type and the type matches', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeTruthy();
-      });
-
-      test('is false if the id is not prefixed', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the id is prefixed with type and namespace', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'foo:hello:world',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test(`is false if the type prefix omits the :`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'helloworld',
-            _source: {
-              type: 'hello',
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the type attribute is missing', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              hello: {},
-              namespace: 'foo',
-            } as any,
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if the type attribute does not match the id', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'jam',
-              jam: {},
-              hello: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
-
-      test('is false if there is no [type] attribute', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        expect(
-          serializer.isRawSavedObject({
-            _id: 'hello:world',
-            _source: {
-              type: 'hello',
-              jam: {},
-              namespace: 'foo',
-            },
-          })
-        ).toBeFalsy();
-      });
+  describe('single-namespace type with a namespace', () => {
+    test('generates an id if none is specified and prefixes namespace', () => {
+      const id = singleNamespaceSerializer.generateRawId('foo', 'goodbye');
+      expect(id).toMatch(/^foo:goodbye\:[\w-]+$/);
+    });
+
+    test('uses the id that is specified and prefixes the namespace', () => {
+      const id = singleNamespaceSerializer.generateRawId('foo', 'hello', 'world');
+      expect(id).toEqual('foo:hello:world');
     });
   });
 
-  describe('#generateRawId', () => {
-    describe('namespaced type without a namespace', () => {
-      test('generates an id if none is specified', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const id = serializer.generateRawId('', 'goodbye');
-        expect(id).toMatch(/goodbye\:[\w-]+$/);
-      });
-
-      test('uses the id that is specified', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const id = serializer.generateRawId('', 'hello', 'world');
-        expect(id).toMatch('hello:world');
-      });
-    });
-
-    describe('namespaced type with a namespace', () => {
-      test('generates an id if none is specified and prefixes namespace', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const id = serializer.generateRawId('foo', 'goodbye');
-        expect(id).toMatch(/foo:goodbye\:[\w-]+$/);
-      });
-
-      test('uses the id that is specified and prefixes the namespace', () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const id = serializer.generateRawId('foo', 'hello', 'world');
-        expect(id).toMatch('foo:hello:world');
-      });
-    });
-
-    describe('namespace agnostic type with a namespace', () => {
-      test(`generates an id if none is specified and doesn't prefix namespace`, () => {
-        typeRegistry.isNamespaceAgnostic.mockReturnValue(true);
-
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const id = serializer.generateRawId('foo', 'goodbye');
-        expect(id).toMatch(/goodbye\:[\w-]+$/);
-      });
-
-      test(`uses the id that is specified and doesn't prefix the namespace`, () => {
-        const serializer = new SavedObjectsSerializer(typeRegistry);
-        const id = serializer.generateRawId('foo', 'hello', 'world');
-        expect(id).toMatch('hello:world');
-      });
+  describe('namespace-agnostic type with a namespace', () => {
+    test(`generates an id if none is specified and doesn't prefix namespace`, () => {
+      const id = namespaceAgnosticSerializer.generateRawId('foo', 'goodbye');
+      expect(id).toMatch(/^goodbye\:[\w-]+$/);
+    });
+
+    test(`uses the id that is specified and doesn't prefix the namespace`, () => {
+      const id = namespaceAgnosticSerializer.generateRawId('foo', 'hello', 'world');
+      expect(id).toEqual('hello:world');
     });
   });
 });
diff --git a/src/core/server/saved_objects/serialization/serializer.ts b/src/core/server/saved_objects/serialization/serializer.ts
index 99d6b0c6b59f9..3b19d494d8ecf 100644
--- a/src/core/server/saved_objects/serialization/serializer.ts
+++ b/src/core/server/saved_objects/serialization/serializer.ts
@@ -49,7 +49,7 @@ export class SavedObjectsSerializer {
   public isRawSavedObject(rawDoc: SavedObjectsRawDoc) {
     const { type, namespace } = rawDoc._source;
     const namespacePrefix =
-      namespace && !this.registry.isNamespaceAgnostic(type) ? `${namespace}:` : '';
+      namespace && this.registry.isSingleNamespace(type) ? `${namespace}:` : '';
     return Boolean(
       type &&
         rawDoc._id.startsWith(`${namespacePrefix}${type}:`) &&
@@ -64,7 +64,7 @@ export class SavedObjectsSerializer {
    */
   public rawToSavedObject(doc: SavedObjectsRawDoc): SavedObjectSanitizedDoc {
     const { _id, _source, _seq_no, _primary_term } = doc;
-    const { type, namespace } = _source;
+    const { type, namespace, namespaces } = _source;
 
     const version =
       _seq_no != null || _primary_term != null
@@ -74,7 +74,8 @@ export class SavedObjectsSerializer {
     return {
       type,
       id: this.trimIdPrefix(namespace, type, _id),
-      ...(namespace && !this.registry.isNamespaceAgnostic(type) && { namespace }),
+      ...(namespace && this.registry.isSingleNamespace(type) && { namespace }),
+      ...(namespaces && this.registry.isMultiNamespace(type) && { namespaces }),
       attributes: _source[type],
       references: _source.references || [],
       ...(_source.migrationVersion && { migrationVersion: _source.migrationVersion }),
@@ -93,6 +94,7 @@ export class SavedObjectsSerializer {
       id,
       type,
       namespace,
+      namespaces,
       attributes,
       migrationVersion,
       updated_at,
@@ -103,7 +105,8 @@ export class SavedObjectsSerializer {
       [type]: attributes,
       type,
       references,
-      ...(namespace && !this.registry.isNamespaceAgnostic(type) && { namespace }),
+      ...(namespace && this.registry.isSingleNamespace(type) && { namespace }),
+      ...(namespaces && this.registry.isMultiNamespace(type) && { namespaces }),
       ...(migrationVersion && { migrationVersion }),
       ...(updated_at && { updated_at }),
     };
@@ -124,7 +127,7 @@ export class SavedObjectsSerializer {
    */
   public generateRawId(namespace: string | undefined, type: string, id?: string) {
     const namespacePrefix =
-      namespace && !this.registry.isNamespaceAgnostic(type) ? `${namespace}:` : '';
+      namespace && this.registry.isSingleNamespace(type) ? `${namespace}:` : '';
     return `${namespacePrefix}${type}:${id || uuid.v1()}`;
   }
 
@@ -133,7 +136,7 @@ export class SavedObjectsSerializer {
     assertNonEmptyString(type, 'saved object type');
 
     const namespacePrefix =
-      namespace && !this.registry.isNamespaceAgnostic(type) ? `${namespace}:` : '';
+      namespace && this.registry.isSingleNamespace(type) ? `${namespace}:` : '';
     const prefix = `${namespacePrefix}${type}:`;
 
     if (!id.startsWith(prefix)) {
diff --git a/src/core/server/saved_objects/serialization/types.ts b/src/core/server/saved_objects/serialization/types.ts
index dfaec127ba159..7ea61f67e9496 100644
--- a/src/core/server/saved_objects/serialization/types.ts
+++ b/src/core/server/saved_objects/serialization/types.ts
@@ -36,6 +36,7 @@ export interface SavedObjectsRawDoc {
 export interface SavedObjectsRawDocSource {
   type: string;
   namespace?: string;
+  namespaces?: string[];
   migrationVersion?: SavedObjectsMigrationVersion;
   updated_at?: string;
   references?: SavedObjectReference[];
@@ -54,6 +55,7 @@ interface SavedObjectDoc {
   id?: string; // NOTE: SavedObjectDoc is used for uncreated objects where `id` is optional
   type: string;
   namespace?: string;
+  namespaces?: string[];
   migrationVersion?: SavedObjectsMigrationVersion;
   version?: string;
   updated_at?: string;
diff --git a/src/core/server/saved_objects/service/lib/__snapshots__/repository.test.js.snap b/src/core/server/saved_objects/service/lib/__snapshots__/repository.test.js.snap
deleted file mode 100644
index 609906c97d599..0000000000000
--- a/src/core/server/saved_objects/service/lib/__snapshots__/repository.test.js.snap
+++ /dev/null
@@ -1,5 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`SavedObjectsRepository #deleteByNamespace requires namespace to be a string 1`] = `"namespace is required, and must be a string"`;
-
-exports[`SavedObjectsRepository #deleteByNamespace requires namespace to be defined 1`] = `"namespace is required, and must be a string"`;
diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts
index 2fd9b487f470a..1fdebd87397eb 100644
--- a/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts
+++ b/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts
@@ -100,6 +100,38 @@ describe('savedObjectsClient/decorateEsError', () => {
     expect(SavedObjectsErrorHelpers.isBadRequestError(error)).toBe(true);
   });
 
+  describe('when es.BadRequest has a reason', () => {
+    it('makes a SavedObjectsClient/esCannotExecuteScriptError error when script context is disabled', () => {
+      const error = new esErrors.BadRequest();
+      (error as Record<string, any>).body = {
+        error: { reason: 'cannot execute scripts using [update] context' },
+      };
+      expect(SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)).toBe(false);
+      expect(decorateEsError(error)).toBe(error);
+      expect(SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)).toBe(true);
+      expect(SavedObjectsErrorHelpers.isBadRequestError(error)).toBe(false);
+    });
+
+    it('makes a SavedObjectsClient/esCannotExecuteScriptError error when inline scripts are disabled', () => {
+      const error = new esErrors.BadRequest();
+      (error as Record<string, any>).body = {
+        error: { reason: 'cannot execute [inline] scripts' },
+      };
+      expect(SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)).toBe(false);
+      expect(decorateEsError(error)).toBe(error);
+      expect(SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)).toBe(true);
+      expect(SavedObjectsErrorHelpers.isBadRequestError(error)).toBe(false);
+    });
+
+    it('makes a SavedObjectsClient/BadRequest error for any other reason', () => {
+      const error = new esErrors.BadRequest();
+      (error as Record<string, any>).body = { error: { reason: 'some other reason' } };
+      expect(SavedObjectsErrorHelpers.isBadRequestError(error)).toBe(false);
+      expect(decorateEsError(error)).toBe(error);
+      expect(SavedObjectsErrorHelpers.isBadRequestError(error)).toBe(true);
+    });
+  });
+
   it('returns other errors as Boom errors', () => {
     const error = new Error();
     expect(error).not.toHaveProperty('isBoom');
diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.ts
index eb9bc89636435..e57f08aa7a527 100644
--- a/src/core/server/saved_objects/service/lib/decorate_es_error.ts
+++ b/src/core/server/saved_objects/service/lib/decorate_es_error.ts
@@ -35,6 +35,8 @@ const {
   NotFound,
   BadRequest,
 } = legacyElasticsearch.errors;
+const SCRIPT_CONTEXT_DISABLED_REGEX = /(?:cannot execute scripts using \[)([a-z]*)(?:\] context)/;
+const INLINE_SCRIPTS_DISABLED_MESSAGE = 'cannot execute [inline] scripts';
 
 import { SavedObjectsErrorHelpers } from './errors';
 
@@ -43,7 +45,7 @@ export function decorateEsError(error: Error) {
     throw new Error('Expected an instance of Error');
   }
 
-  const { reason } = get(error, 'body.error', { reason: undefined });
+  const { reason } = get(error, 'body.error', { reason: undefined }) as { reason?: string };
   if (
     error instanceof ConnectionFault ||
     error instanceof ServiceUnavailable ||
@@ -74,6 +76,12 @@ export function decorateEsError(error: Error) {
   }
 
   if (error instanceof BadRequest) {
+    if (
+      SCRIPT_CONTEXT_DISABLED_REGEX.test(reason || '') ||
+      reason === INLINE_SCRIPTS_DISABLED_MESSAGE
+    ) {
+      return SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(error, reason);
+    }
     return SavedObjectsErrorHelpers.decorateBadRequestError(error, reason);
   }
 
diff --git a/src/core/server/saved_objects/service/lib/errors.test.ts b/src/core/server/saved_objects/service/lib/errors.test.ts
index 12fc913f93090..4a43835d795d1 100644
--- a/src/core/server/saved_objects/service/lib/errors.test.ts
+++ b/src/core/server/saved_objects/service/lib/errors.test.ts
@@ -34,6 +34,7 @@ describe('savedObjectsClient/errorTypes', () => {
       });
 
       it('has boom properties', () => {
+        expect(errorObj).toHaveProperty('isBoom', true);
         expect(errorObj.output.payload).toMatchObject({
           statusCode: 400,
           message: "Unsupported saved object type: 'someType': Bad Request",
@@ -57,6 +58,7 @@ describe('savedObjectsClient/errorTypes', () => {
       });
 
       it('has boom properties', () => {
+        expect(errorObj).toHaveProperty('isBoom', true);
         expect(errorObj.output.payload).toMatchObject({
           statusCode: 400,
           message: 'test reason message: Bad Request',
@@ -80,14 +82,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('adds boom properties', () => {
         const error = SavedObjectsErrorHelpers.decorateBadRequestError(new Error());
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(400);
-      });
-
-      it('preserves boom properties of input', () => {
-        const error = Boom.notFound();
-        SavedObjectsErrorHelpers.decorateBadRequestError(error);
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -95,6 +90,7 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.decorateBadRequestError(new Error('foobar'));
           expect(error.output.payload).toHaveProperty('message', 'foobar');
         });
+
         it('prefixes message with passed reason', () => {
           const error = SavedObjectsErrorHelpers.decorateBadRequestError(
             new Error('foobar'),
@@ -102,13 +98,21 @@ describe('savedObjectsClient/errorTypes', () => {
           );
           expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
         });
+
         it('sets statusCode to 400', () => {
           const error = SavedObjectsErrorHelpers.decorateBadRequestError(new Error('foo'));
           expect(error.output).toHaveProperty('statusCode', 400);
         });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateBadRequestError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
       });
     });
   });
+
   describe('NotAuthorized error', () => {
     describe('decorateNotAuthorizedError', () => {
       it('returns original object', () => {
@@ -125,14 +129,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('adds boom properties', () => {
         const error = SavedObjectsErrorHelpers.decorateNotAuthorizedError(new Error());
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(401);
-      });
-
-      it('preserves boom properties of input', () => {
-        const error = Boom.notFound();
-        SavedObjectsErrorHelpers.decorateNotAuthorizedError(error);
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -140,6 +137,7 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.decorateNotAuthorizedError(new Error('foobar'));
           expect(error.output.payload).toHaveProperty('message', 'foobar');
         });
+
         it('prefixes message with passed reason', () => {
           const error = SavedObjectsErrorHelpers.decorateNotAuthorizedError(
             new Error('foobar'),
@@ -147,13 +145,21 @@ describe('savedObjectsClient/errorTypes', () => {
           );
           expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
         });
+
         it('sets statusCode to 401', () => {
           const error = SavedObjectsErrorHelpers.decorateNotAuthorizedError(new Error('foo'));
           expect(error.output).toHaveProperty('statusCode', 401);
         });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateNotAuthorizedError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
       });
     });
   });
+
   describe('Forbidden error', () => {
     describe('decorateForbiddenError', () => {
       it('returns original object', () => {
@@ -170,14 +176,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('adds boom properties', () => {
         const error = SavedObjectsErrorHelpers.decorateForbiddenError(new Error());
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(403);
-      });
-
-      it('preserves boom properties of input', () => {
-        const error = Boom.notFound();
-        SavedObjectsErrorHelpers.decorateForbiddenError(error);
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -185,17 +184,26 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.decorateForbiddenError(new Error('foobar'));
           expect(error.output.payload).toHaveProperty('message', 'foobar');
         });
+
         it('prefixes message with passed reason', () => {
           const error = SavedObjectsErrorHelpers.decorateForbiddenError(new Error('foobar'), 'biz');
           expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
         });
+
         it('sets statusCode to 403', () => {
           const error = SavedObjectsErrorHelpers.decorateForbiddenError(new Error('foo'));
           expect(error.output).toHaveProperty('statusCode', 403);
         });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateForbiddenError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
       });
     });
   });
+
   describe('NotFound error', () => {
     describe('createGenericNotFoundError', () => {
       it('makes an error identifiable as a NotFound error', () => {
@@ -203,11 +211,9 @@ describe('savedObjectsClient/errorTypes', () => {
         expect(SavedObjectsErrorHelpers.isNotFoundError(error)).toBe(true);
       });
 
-      it('is a boom error, has boom properties', () => {
+      it('returns a boom error', () => {
         const error = SavedObjectsErrorHelpers.createGenericNotFoundError();
-        expect(error).toHaveProperty('isBoom');
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -215,6 +221,7 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.createGenericNotFoundError();
           expect(error.output.payload).toHaveProperty('message', 'Not Found');
         });
+
         it('sets statusCode to 404', () => {
           const error = SavedObjectsErrorHelpers.createGenericNotFoundError();
           expect(error.output).toHaveProperty('statusCode', 404);
@@ -222,6 +229,7 @@ describe('savedObjectsClient/errorTypes', () => {
       });
     });
   });
+
   describe('Conflict error', () => {
     describe('decorateConflictError', () => {
       it('returns original object', () => {
@@ -238,14 +246,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('adds boom properties', () => {
         const error = SavedObjectsErrorHelpers.decorateConflictError(new Error());
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(409);
-      });
-
-      it('preserves boom properties of input', () => {
-        const error = Boom.notFound();
-        SavedObjectsErrorHelpers.decorateConflictError(error);
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -253,17 +254,77 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.decorateConflictError(new Error('foobar'));
           expect(error.output.payload).toHaveProperty('message', 'foobar');
         });
+
         it('prefixes message with passed reason', () => {
           const error = SavedObjectsErrorHelpers.decorateConflictError(new Error('foobar'), 'biz');
           expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
         });
+
         it('sets statusCode to 409', () => {
           const error = SavedObjectsErrorHelpers.decorateConflictError(new Error('foo'));
           expect(error.output).toHaveProperty('statusCode', 409);
         });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateConflictError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
+      });
+    });
+  });
+
+  describe('EsCannotExecuteScript error', () => {
+    describe('decorateEsCannotExecuteScriptError', () => {
+      it('returns original object', () => {
+        const error = new Error();
+        expect(SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(error)).toBe(error);
+      });
+
+      it('makes the error identifiable as a EsCannotExecuteScript error', () => {
+        const error = new Error();
+        expect(SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)).toBe(false);
+        SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(error);
+        expect(SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)).toBe(true);
+      });
+
+      it('adds boom properties', () => {
+        const error = SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(new Error());
+        expect(error).toHaveProperty('isBoom', true);
+      });
+
+      describe('error.output', () => {
+        it('defaults to message of error', () => {
+          const error = SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(
+            new Error('foobar')
+          );
+          expect(error.output.payload).toHaveProperty('message', 'foobar');
+        });
+
+        it('prefixes message with passed reason', () => {
+          const error = SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(
+            new Error('foobar'),
+            'biz'
+          );
+          expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
+        });
+
+        it('sets statusCode to 501', () => {
+          const error = SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(
+            new Error('foo')
+          );
+          expect(error.output).toHaveProperty('statusCode', 400);
+        });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
       });
     });
   });
+
   describe('EsUnavailable error', () => {
     describe('decorateEsUnavailableError', () => {
       it('returns original object', () => {
@@ -280,14 +341,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('adds boom properties', () => {
         const error = SavedObjectsErrorHelpers.decorateEsUnavailableError(new Error());
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(503);
-      });
-
-      it('preserves boom properties of input', () => {
-        const error = Boom.notFound();
-        SavedObjectsErrorHelpers.decorateEsUnavailableError(error);
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -295,6 +349,7 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.decorateEsUnavailableError(new Error('foobar'));
           expect(error.output.payload).toHaveProperty('message', 'foobar');
         });
+
         it('prefixes message with passed reason', () => {
           const error = SavedObjectsErrorHelpers.decorateEsUnavailableError(
             new Error('foobar'),
@@ -302,13 +357,21 @@ describe('savedObjectsClient/errorTypes', () => {
           );
           expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
         });
+
         it('sets statusCode to 503', () => {
           const error = SavedObjectsErrorHelpers.decorateEsUnavailableError(new Error('foo'));
           expect(error.output).toHaveProperty('statusCode', 503);
         });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateEsUnavailableError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
       });
     });
   });
+
   describe('General error', () => {
     describe('decorateGeneralError', () => {
       it('returns original object', () => {
@@ -318,14 +381,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('adds boom properties', () => {
         const error = SavedObjectsErrorHelpers.decorateGeneralError(new Error());
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(500);
-      });
-
-      it('preserves boom properties of input', () => {
-        const error = Boom.notFound();
-        SavedObjectsErrorHelpers.decorateGeneralError(error);
-        expect(error.output.statusCode).toBe(404);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -333,10 +389,17 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.decorateGeneralError(new Error('foobar'));
           expect(error.output.payload.message).toMatch(/internal server error/i);
         });
+
         it('sets statusCode to 500', () => {
           const error = SavedObjectsErrorHelpers.decorateGeneralError(new Error('foo'));
           expect(error.output).toHaveProperty('statusCode', 500);
         });
+
+        it('preserves boom properties of input', () => {
+          const error = Boom.notFound();
+          SavedObjectsErrorHelpers.decorateGeneralError(error);
+          expect(error.output).toHaveProperty('statusCode', 404);
+        });
       });
     });
   });
@@ -363,9 +426,7 @@ describe('savedObjectsClient/errorTypes', () => {
 
       it('returns a boom error', () => {
         const error = SavedObjectsErrorHelpers.createEsAutoCreateIndexError();
-        expect(error).toHaveProperty('isBoom');
-        expect(typeof error.output).toBe('object');
-        expect(error.output.statusCode).toBe(503);
+        expect(error).toHaveProperty('isBoom', true);
       });
 
       describe('error.output', () => {
@@ -373,6 +434,7 @@ describe('savedObjectsClient/errorTypes', () => {
           const error = SavedObjectsErrorHelpers.createEsAutoCreateIndexError();
           expect(error.output.payload).toHaveProperty('message', 'Automatic index creation failed');
         });
+
         it('sets statusCode to 503', () => {
           const error = SavedObjectsErrorHelpers.createEsAutoCreateIndexError();
           expect(error.output).toHaveProperty('statusCode', 503);
diff --git a/src/core/server/saved_objects/service/lib/errors.ts b/src/core/server/saved_objects/service/lib/errors.ts
index e9138e9b8a347..478c6b6d26d53 100644
--- a/src/core/server/saved_objects/service/lib/errors.ts
+++ b/src/core/server/saved_objects/service/lib/errors.ts
@@ -33,6 +33,8 @@ const CODE_REQUEST_ENTITY_TOO_LARGE = 'SavedObjectsClient/requestEntityTooLarge'
 const CODE_NOT_FOUND = 'SavedObjectsClient/notFound';
 // 409 - Conflict
 const CODE_CONFLICT = 'SavedObjectsClient/conflict';
+// 400 - Es Cannot Execute Script
+const CODE_ES_CANNOT_EXECUTE_SCRIPT = 'SavedObjectsClient/esCannotExecuteScript';
 // 503 - Es Unavailable
 const CODE_ES_UNAVAILABLE = 'SavedObjectsClient/esUnavailable';
 // 503 - Unable to automatically create index because of action.auto_create_index setting
@@ -152,10 +154,24 @@ export class SavedObjectsErrorHelpers {
     return decorate(error, CODE_CONFLICT, 409, reason);
   }
 
+  public static createConflictError(type: string, id: string) {
+    return SavedObjectsErrorHelpers.decorateConflictError(
+      Boom.conflict(`Saved object [${type}/${id}] conflict`)
+    );
+  }
+
   public static isConflictError(error: Error | DecoratedError) {
     return isSavedObjectsClientError(error) && error[code] === CODE_CONFLICT;
   }
 
+  public static decorateEsCannotExecuteScriptError(error: Error, reason?: string) {
+    return decorate(error, CODE_ES_CANNOT_EXECUTE_SCRIPT, 400, reason);
+  }
+
+  public static isEsCannotExecuteScriptError(error: Error | DecoratedError) {
+    return isSavedObjectsClientError(error) && error[code] === CODE_ES_CANNOT_EXECUTE_SCRIPT;
+  }
+
   public static decorateEsUnavailableError(error: Error, reason?: string) {
     return decorate(error, CODE_ES_UNAVAILABLE, 503, reason);
   }
diff --git a/src/core/server/saved_objects/service/lib/included_fields.test.ts b/src/core/server/saved_objects/service/lib/included_fields.test.ts
index 40d6552c2ad5f..ced99361f1ea0 100644
--- a/src/core/server/saved_objects/service/lib/included_fields.test.ts
+++ b/src/core/server/saved_objects/service/lib/included_fields.test.ts
@@ -26,7 +26,7 @@ describe('includedFields', () => {
 
   it('accepts type string', () => {
     const fields = includedFields('config', 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('type');
   });
 
@@ -37,6 +37,7 @@ Array [
   "config.foo",
   "secret.foo",
   "namespace",
+  "namespaces",
   "type",
   "references",
   "migrationVersion",
@@ -48,14 +49,14 @@ Array [
 
   it('accepts field as string', () => {
     const fields = includedFields('config', 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('config.foo');
   });
 
   it('accepts fields as an array', () => {
     const fields = includedFields('config', ['foo', 'bar']);
 
-    expect(fields).toHaveLength(9);
+    expect(fields).toHaveLength(10);
     expect(fields).toContain('config.foo');
     expect(fields).toContain('config.bar');
   });
@@ -69,6 +70,7 @@ Array [
   "secret.foo",
   "secret.bar",
   "namespace",
+  "namespaces",
   "type",
   "references",
   "migrationVersion",
@@ -81,31 +83,37 @@ Array [
 
   it('includes namespace', () => {
     const fields = includedFields('config', 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('namespace');
   });
 
+  it('includes namespaces', () => {
+    const fields = includedFields('config', 'foo');
+    expect(fields).toHaveLength(8);
+    expect(fields).toContain('namespaces');
+  });
+
   it('includes references', () => {
     const fields = includedFields('config', 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('references');
   });
 
   it('includes migrationVersion', () => {
     const fields = includedFields('config', 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('migrationVersion');
   });
 
   it('includes updated_at', () => {
     const fields = includedFields('config', 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('updated_at');
   });
 
   it('uses wildcard when type is not provided', () => {
     const fields = includedFields(undefined, 'foo');
-    expect(fields).toHaveLength(7);
+    expect(fields).toHaveLength(8);
     expect(fields).toContain('*.foo');
   });
 
@@ -113,7 +121,7 @@ Array [
     it('includes legacy field path', () => {
       const fields = includedFields('config', ['foo', 'bar']);
 
-      expect(fields).toHaveLength(9);
+      expect(fields).toHaveLength(10);
       expect(fields).toContain('foo');
       expect(fields).toContain('bar');
     });
diff --git a/src/core/server/saved_objects/service/lib/included_fields.ts b/src/core/server/saved_objects/service/lib/included_fields.ts
index f372db5a1a635..c50ac22594008 100644
--- a/src/core/server/saved_objects/service/lib/included_fields.ts
+++ b/src/core/server/saved_objects/service/lib/included_fields.ts
@@ -37,6 +37,7 @@ export function includedFields(type: string | string[] = '*', fields?: string[]
       return [...acc, ...sourceFields.map(f => `${t}.${f}`)];
     }, [])
     .concat('namespace')
+    .concat('namespaces')
     .concat('type')
     .concat('references')
     .concat('migrationVersion')
diff --git a/src/core/server/saved_objects/service/lib/repository.mock.ts b/src/core/server/saved_objects/service/lib/repository.mock.ts
index e69c0ff37d1be..afef378b7307b 100644
--- a/src/core/server/saved_objects/service/lib/repository.mock.ts
+++ b/src/core/server/saved_objects/service/lib/repository.mock.ts
@@ -28,6 +28,8 @@ const create = (): jest.Mocked<ISavedObjectsRepository> => ({
   find: jest.fn(),
   get: jest.fn(),
   update: jest.fn(),
+  addToNamespaces: jest.fn(),
+  deleteFromNamespaces: jest.fn(),
   deleteByNamespace: jest.fn(),
   incrementCounter: jest.fn(),
 });
diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js
index 2e5eeec04e0a8..927171438ae99 100644
--- a/src/core/server/saved_objects/service/lib/repository.test.js
+++ b/src/core/server/saved_objects/service/lib/repository.test.js
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import _ from 'lodash';
 
 import { SavedObjectsRepository } from './repository';
 import * as getSearchDslNS from './search_dsl/search_dsl';
@@ -30,162 +29,31 @@ jest.mock('./search_dsl/search_dsl', () => ({ getSearchDsl: jest.fn() }));
 // BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository
 // so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient.
 
+const createBadRequestError = (...args) =>
+  SavedObjectsErrorHelpers.createBadRequestError(...args).output.payload;
+const createConflictError = (...args) =>
+  SavedObjectsErrorHelpers.createConflictError(...args).output.payload;
+const createGenericNotFoundError = (...args) =>
+  SavedObjectsErrorHelpers.createGenericNotFoundError(...args).output.payload;
+const createUnsupportedTypeError = (...args) =>
+  SavedObjectsErrorHelpers.createUnsupportedTypeError(...args).output.payload;
+
 describe('SavedObjectsRepository', () => {
   let callAdminCluster;
   let savedObjectsRepository;
   let migrator;
 
+  let serializer;
   const mockTimestamp = '2017-08-14T15:49:14.886Z';
   const mockTimestampFields = { updated_at: mockTimestamp };
   const mockVersionProps = { _seq_no: 1, _primary_term: 1 };
   const mockVersion = encodeHitVersion(mockVersionProps);
-  const noNamespaceSearchResults = {
-    hits: {
-      total: 4,
-      hits: [
-        {
-          _index: '.kibana',
-          _id: 'index-pattern:logstash-*',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            type: 'index-pattern',
-            ...mockTimestampFields,
-            'index-pattern': {
-              title: 'logstash-*',
-              timeFieldName: '@timestamp',
-              notExpandable: true,
-            },
-          },
-        },
-        {
-          _index: '.kibana',
-          _id: 'config:6.0.0-alpha1',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            type: 'config',
-            ...mockTimestampFields,
-            config: {
-              buildNum: 8467,
-              defaultIndex: 'logstash-*',
-            },
-          },
-        },
-        {
-          _index: '.kibana',
-          _id: 'index-pattern:stocks-*',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            type: 'index-pattern',
-            ...mockTimestampFields,
-            'index-pattern': {
-              title: 'stocks-*',
-              timeFieldName: '@timestamp',
-              notExpandable: true,
-            },
-          },
-        },
-        {
-          _index: '.kibana',
-          _id: 'globaltype:something',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            type: 'globaltype',
-            ...mockTimestampFields,
-            globaltype: {
-              name: 'bar',
-            },
-          },
-        },
-      ],
-    },
-  };
-
-  const namespacedSearchResults = {
-    hits: {
-      total: 4,
-      hits: [
-        {
-          _index: '.kibana',
-          _id: 'foo-namespace:index-pattern:logstash-*',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            namespace: 'foo-namespace',
-            type: 'index-pattern',
-            ...mockTimestampFields,
-            'index-pattern': {
-              title: 'logstash-*',
-              timeFieldName: '@timestamp',
-              notExpandable: true,
-            },
-          },
-        },
-        {
-          _index: '.kibana',
-          _id: 'foo-namespace:config:6.0.0-alpha1',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            namespace: 'foo-namespace',
-            type: 'config',
-            ...mockTimestampFields,
-            config: {
-              buildNum: 8467,
-              defaultIndex: 'logstash-*',
-            },
-          },
-        },
-        {
-          _index: '.kibana',
-          _id: 'foo-namespace:index-pattern:stocks-*',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            namespace: 'foo-namespace',
-            type: 'index-pattern',
-            ...mockTimestampFields,
-            'index-pattern': {
-              title: 'stocks-*',
-              timeFieldName: '@timestamp',
-              notExpandable: true,
-            },
-          },
-        },
-        {
-          _index: '.kibana',
-          _id: 'globaltype:something',
-          _score: 1,
-          ...mockVersionProps,
-          _source: {
-            type: 'globaltype',
-            ...mockTimestampFields,
-            globaltype: {
-              name: 'bar',
-            },
-          },
-        },
-      ],
-    },
-  };
 
-  const deleteByQueryResults = {
-    took: 27,
-    timed_out: false,
-    total: 23,
-    deleted: 23,
-    batches: 1,
-    version_conflicts: 0,
-    noops: 0,
-    retries: { bulk: 0, search: 0 },
-    throttled_millis: 0,
-    requests_per_second: -1,
-    throttled_until_millis: 0,
-    failures: [],
-  };
+  const CUSTOM_INDEX_TYPE = 'customIndex';
+  const NAMESPACE_AGNOSTIC_TYPE = 'globalType';
+  const MULTI_NAMESPACE_TYPE = 'shareableType';
+  const MULTI_NAMESPACE_CUSTOM_INDEX_TYPE = 'shareableTypeCustomIndex';
+  const HIDDEN_TYPE = 'hiddenType';
 
   const mappings = {
     properties: {
@@ -194,43 +62,47 @@ describe('SavedObjectsRepository', () => {
           type: 'keyword',
         },
       },
-      foo: {
+      'index-pattern': {
         properties: {
-          type: 'keyword',
+          someField: {
+            type: 'keyword',
+          },
         },
       },
-      bar: {
+      dashboard: {
         properties: {
-          type: 'keyword',
+          otherField: {
+            type: 'keyword',
+          },
         },
       },
-      baz: {
+      [CUSTOM_INDEX_TYPE]: {
         properties: {
           type: 'keyword',
         },
       },
-      'index-pattern': {
+      [NAMESPACE_AGNOSTIC_TYPE]: {
         properties: {
-          someField: {
+          yetAnotherField: {
             type: 'keyword',
           },
         },
       },
-      dashboard: {
+      [MULTI_NAMESPACE_TYPE]: {
         properties: {
-          otherField: {
+          evenYetAnotherField: {
             type: 'keyword',
           },
         },
       },
-      globaltype: {
+      [MULTI_NAMESPACE_CUSTOM_INDEX_TYPE]: {
         properties: {
-          yetAnotherField: {
+          evenYetAnotherField: {
             type: 'keyword',
           },
         },
       },
-      hiddenType: {
+      [HIDDEN_TYPE]: {
         properties: {
           someField: {
             type: 'keyword',
@@ -240,96 +112,97 @@ describe('SavedObjectsRepository', () => {
     },
   };
 
-  const typeRegistry = new SavedObjectTypeRegistry();
-  typeRegistry.registerType({
-    name: 'config',
-    hidden: false,
-    namespaceAgnostic: false,
-    mappings: {
-      properties: {
-        type: 'keyword',
-      },
-    },
+  const createType = type => ({
+    name: type,
+    mappings: { properties: mappings.properties[type].properties },
   });
-  typeRegistry.registerType({
-    name: 'index-pattern',
-    hidden: false,
-    namespaceAgnostic: false,
-    mappings: {
-      properties: {
-        someField: {
-          type: 'keyword',
-        },
-      },
-    },
+
+  const registry = new SavedObjectTypeRegistry();
+  registry.registerType(createType('config'));
+  registry.registerType(createType('index-pattern'));
+  registry.registerType(createType('dashboard'));
+  registry.registerType({
+    ...createType(CUSTOM_INDEX_TYPE),
+    indexPattern: 'custom',
   });
-  typeRegistry.registerType({
-    name: 'dashboard',
-    hidden: false,
-    namespaceAgnostic: false,
-    mappings: {
-      properties: {
-        otherField: {
-          type: 'keyword',
-        },
-      },
-    },
+  registry.registerType({
+    ...createType(NAMESPACE_AGNOSTIC_TYPE),
+    namespaceType: 'agnostic',
   });
-  typeRegistry.registerType({
-    name: 'globaltype',
-    hidden: false,
-    namespaceAgnostic: true,
-    mappings: {
-      properties: {
-        yetAnotherField: {
-          type: 'keyword',
-        },
-      },
-    },
+  registry.registerType({
+    ...createType(MULTI_NAMESPACE_TYPE),
+    namespaceType: 'multiple',
   });
-  typeRegistry.registerType({
-    name: 'foo',
-    hidden: false,
-    namespaceAgnostic: true,
-    mappings: {
-      properties: {
-        type: 'keyword',
-      },
-    },
+  registry.registerType({
+    ...createType(MULTI_NAMESPACE_CUSTOM_INDEX_TYPE),
+    namespaceType: 'multiple',
+    indexPattern: 'custom',
   });
-  typeRegistry.registerType({
-    name: 'bar',
-    hidden: false,
-    namespaceAgnostic: true,
-    mappings: {
-      properties: {
-        type: 'keyword',
-      },
-    },
+  registry.registerType({
+    ...createType(HIDDEN_TYPE),
+    hidden: true,
+    namespaceType: 'agnostic',
   });
-  typeRegistry.registerType({
-    name: 'baz',
-    hidden: false,
-    namespaceAgnostic: false,
-    indexPattern: 'beats',
-    mappings: {
-      properties: {
-        type: 'keyword',
-      },
+
+  const getMockGetResponse = ({ type, id, references, namespace }) => ({
+    // NOTE: Elasticsearch returns more fields (_index, _type) but the SavedObjectsRepository method ignores these
+    found: true,
+    _id: `${registry.isSingleNamespace(type) && namespace ? `${namespace}:` : ''}${type}:${id}`,
+    ...mockVersionProps,
+    _source: {
+      ...(registry.isSingleNamespace(type) && { namespace }),
+      ...(registry.isMultiNamespace(type) && { namespaces: [namespace ?? 'default'] }),
+      type,
+      [type]: { title: 'Testing' },
+      references,
+      specialProperty: 'specialValue',
+      ...mockTimestampFields,
     },
   });
-  typeRegistry.registerType({
-    name: 'hiddenType',
-    hidden: true,
-    namespaceAgnostic: true,
-    mappings: {
-      properties: {
-        someField: {
-          type: 'keyword',
-        },
-      },
+
+  const getMockMgetResponse = (objects, namespace) => ({
+    status: 200,
+    docs: objects.map(obj =>
+      obj.found === false ? obj : getMockGetResponse({ ...obj, namespace })
+    ),
+  });
+
+  const expectClusterCalls = (...actions) => {
+    for (let i = 0; i < actions.length; i++) {
+      expect(callAdminCluster).toHaveBeenNthCalledWith(i + 1, actions[i], expect.any(Object));
+    }
+    expect(callAdminCluster).toHaveBeenCalledTimes(actions.length);
+  };
+  const expectClusterCallArgs = (args, n = 1) => {
+    expect(callAdminCluster).toHaveBeenNthCalledWith(
+      n,
+      expect.any(String),
+      expect.objectContaining(args)
+    );
+  };
+
+  expect.extend({
+    toBeDocumentWithoutError(received, type, id) {
+      if (received.type === type && received.id === id && !received.error) {
+        return { message: () => `expected type and id not to match without error`, pass: true };
+      } else {
+        return { message: () => `expected type and id to match without error`, pass: false };
+      }
     },
   });
+  const expectSuccess = ({ type, id }) => expect.toBeDocumentWithoutError(type, id);
+  const expectError = ({ type, id }) => ({ type, id, error: expect.any(Object) });
+  const expectErrorResult = ({ type, id }, error) => ({ type, id, error });
+  const expectErrorNotFound = obj =>
+    expectErrorResult(obj, createGenericNotFoundError(obj.type, obj.id));
+  const expectErrorConflict = obj => expectErrorResult(obj, createConflictError(obj.type, obj.id));
+  const expectErrorInvalidType = obj =>
+    expectErrorResult(obj, createUnsupportedTypeError(obj.type, obj.id));
+
+  const expectMigrationArgs = (args, contains = true, n = 1) => {
+    const obj = contains ? expect.objectContaining(args) : expect.not.objectContaining(args);
+    expect(migrator.migrateDocument).toHaveBeenNthCalledWith(n, obj);
+  };
 
   beforeEach(() => {
     callAdminCluster = jest.fn();
@@ -338,16 +211,28 @@ describe('SavedObjectsRepository', () => {
       runMigrations: async () => ({ status: 'skipped' }),
     };
 
-    const serializer = new SavedObjectsSerializer(typeRegistry);
-    const allTypes = typeRegistry.getAllTypes().map(type => type.name);
-    const allowedTypes = [...new Set(allTypes.filter(type => !typeRegistry.isHidden(type)))];
+    // create a mock serializer "shim" so we can track function calls, but use the real serializer's implementation
+    serializer = {
+      isRawSavedObject: jest.fn(),
+      rawToSavedObject: jest.fn(),
+      savedObjectToRaw: jest.fn(),
+      generateRawId: jest.fn(),
+      trimIdPrefix: jest.fn(),
+    };
+    const _serializer = new SavedObjectsSerializer(registry);
+    Object.keys(serializer).forEach(key => {
+      serializer[key].mockImplementation((...args) => _serializer[key](...args));
+    });
+
+    const allTypes = registry.getAllTypes().map(type => type.name);
+    const allowedTypes = [...new Set(allTypes.filter(type => !registry.isHidden(type)))];
 
     savedObjectsRepository = new SavedObjectsRepository({
       index: '.kibana-test',
       mappings,
       callCluster: callAdminCluster,
       migrator,
-      typeRegistry,
+      typeRegistry: registry,
       serializer,
       allowedTypes,
     });
@@ -356,2644 +241,2819 @@ describe('SavedObjectsRepository', () => {
     getSearchDslNS.getSearchDsl.mockReset();
   });
 
-  describe('#create', () => {
-    beforeEach(() => {
-      callAdminCluster.mockImplementation((method, params) => ({
-        _id: params.id,
-        ...mockVersionProps,
-      }));
-    });
+  const mockMigrationVersion = { foo: '2.3.4' };
+  const mockMigrateDocument = doc => ({
+    ...doc,
+    attributes: {
+      ...doc.attributes,
+      ...(doc.attributes?.title && { title: `${doc.attributes.title}!!` }),
+    },
+    migrationVersion: mockMigrationVersion,
+    references: [{ name: 'search_0', type: 'search', id: '123' }],
+  });
 
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
+  describe('#addToNamespaces', () => {
+    const id = 'some-id';
+    const type = MULTI_NAMESPACE_TYPE;
+    const currentNs1 = 'default';
+    const currentNs2 = 'foo-namespace';
+    const newNs1 = 'bar-namespace';
+    const newNs2 = 'baz-namespace';
+
+    const mockGetResponse = (type, id) => {
+      // mock a document that exists in two namespaces
+      const mockResponse = getMockGetResponse({ type, id });
+      mockResponse._source.namespaces = [currentNs1, currentNs2];
+      callAdminCluster.mockResolvedValueOnce(mockResponse); // this._callCluster('get', ...)
+    };
 
-      await expect(
-        savedObjectsRepository.create(
-          'index-pattern',
-          {
-            title: 'Logstash',
-          },
-          {
-            id: 'logstash-*',
-            namespace: 'foo-namespace',
-          }
-        )
-      ).resolves.toBeDefined();
-      expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
-    });
+    const addToNamespacesSuccess = async (type, id, namespaces, options) => {
+      mockGetResponse(type, id); // this._callCluster('get', ...)
+      callAdminCluster.mockResolvedValue({
+        _id: `${type}:${id}`,
+        ...mockVersionProps,
+        result: 'updated',
+      }); // this._writeToCluster('update', ...)
+      const result = await savedObjectsRepository.addToNamespaces(type, id, namespaces, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(2);
+      return result;
+    };
 
-    it('formats Elasticsearch response', async () => {
-      const response = await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          title: 'Logstash',
-        },
-        {
-          id: 'logstash-*',
-          namespace: 'foo-namespace',
-          references: [
-            {
-              name: 'ref_0',
-              type: 'test',
-              id: '123',
-            },
-          ],
-        }
-      );
+    describe('cluster calls', () => {
+      it(`should use ES get action then update action`, async () => {
+        await addToNamespacesSuccess(type, id, [newNs1, newNs2]);
+        expectClusterCalls('get', 'update');
+      });
 
-      expect(response).toEqual({
-        type: 'index-pattern',
-        id: 'logstash-*',
-        ...mockTimestampFields,
-        version: mockVersion,
-        attributes: {
-          title: 'Logstash',
-        },
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '123',
-          },
-        ],
+      it(`defaults to the version of the existing document`, async () => {
+        await addToNamespacesSuccess(type, id, [newNs1, newNs2]);
+        const versionProperties = {
+          if_seq_no: mockVersionProps._seq_no,
+          if_primary_term: mockVersionProps._primary_term,
+        };
+        expectClusterCallArgs(versionProperties, 2);
+      });
+
+      it(`accepts version`, async () => {
+        await addToNamespacesSuccess(type, id, [newNs1, newNs2], {
+          version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }),
+        });
+        expectClusterCallArgs({ if_seq_no: 100, if_primary_term: 200 }, 2);
       });
-    });
 
-    it('should use ES index action', async () => {
-      await savedObjectsRepository.create('index-pattern', {
-        id: 'logstash-*',
-        title: 'Logstash',
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await addToNamespacesSuccess(type, id, [newNs1, newNs2]);
+        expectClusterCallArgs({ refresh: 'wait_for' }, 2);
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('index', expect.any(Object));
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await addToNamespacesSuccess(type, id, [newNs1, newNs2], { refresh });
+        expectClusterCallArgs({ refresh }, 2);
+      });
     });
 
-    it('should use default index', async () => {
-      await savedObjectsRepository.create('index-pattern', {
-        id: 'logstash-*',
-        title: 'Logstash',
+    describe('errors', () => {
+      const expectNotFoundError = async (type, id, namespaces, options) => {
+        await expect(
+          savedObjectsRepository.addToNamespaces(type, id, namespaces, options)
+        ).rejects.toThrowError(createGenericNotFoundError(type, id));
+      };
+      const expectBadRequestError = async (type, id, namespaces, message) => {
+        await expect(
+          savedObjectsRepository.addToNamespaces(type, id, namespaces)
+        ).rejects.toThrowError(createBadRequestError(message));
+      };
+
+      it(`throws when type is invalid`, async () => {
+        await expectNotFoundError('unknownType', id, [newNs1, newNs2]);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'index',
-        expect.objectContaining({
-          index: '.kibana-test',
-        })
-      );
-    });
+      it(`throws when type is hidden`, async () => {
+        await expectNotFoundError(HIDDEN_TYPE, id, [newNs1, newNs2]);
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-    it('should use custom index', async () => {
-      await savedObjectsRepository.create('baz', {
-        id: 'logstash-*',
-        title: 'Logstash',
+      it(`throws when type is not multi-namespace`, async () => {
+        const test = async type => {
+          const message = `${type} doesn't support multiple namespaces`;
+          await expectBadRequestError(type, id, [newNs1, newNs2], message);
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
+        await test('index-pattern');
+        await test(NAMESPACE_AGNOSTIC_TYPE);
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'index',
-        expect.objectContaining({
-          index: 'beats',
-        })
-      );
-    });
+      it(`throws when namespaces is an empty array`, async () => {
+        const test = async namespaces => {
+          const message = 'namespaces must be a non-empty array of strings';
+          await expectBadRequestError(type, id, namespaces, message);
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
+        await test([]);
+      });
 
-    it('migrates the doc', async () => {
-      migrator.migrateDocument = doc => {
-        doc.attributes.title = doc.attributes.title + '!!';
-        doc.migrationVersion = { foo: '2.3.4' };
-        doc.references = [{ name: 'search_0', type: 'search', id: '123' }];
-        return doc;
-      };
+      it(`throws when ES is unable to find the document during get`, async () => {
+        callAdminCluster.mockResolvedValue({ found: false }); // this._callCluster('get', ...)
+        await expectNotFoundError(type, id, [newNs1, newNs2]);
+        expectClusterCalls('get');
+      });
 
-      await savedObjectsRepository.create('index-pattern', {
-        id: 'logstash-*',
-        title: 'Logstash',
+      it(`throws when ES is unable to find the index during get`, async () => {
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._callCluster('get', ...)
+        await expectNotFoundError(type, id, [newNs1, newNs2]);
+        expectClusterCalls('get');
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        body: {
-          'index-pattern': { id: 'logstash-*', title: 'Logstash!!' },
-          migrationVersion: { foo: '2.3.4' },
-          type: 'index-pattern',
-          updated_at: '2017-08-14T15:49:14.886Z',
-          references: [{ name: 'search_0', type: 'search', id: '123' }],
-        },
+      it(`throws when the document exists, but not in this namespace`, async () => {
+        mockGetResponse(type, id); // this._callCluster('get', ...)
+        await expectNotFoundError(type, id, [newNs1, newNs2], {
+          namespace: 'some-other-namespace',
+        });
+        expectClusterCalls('get');
       });
-    });
 
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      await savedObjectsRepository.create('index-pattern', {
-        id: 'logstash-*',
-        title: 'Logstash',
+      it(`throws when ES is unable to find the document during update`, async () => {
+        mockGetResponse(type, id); // this._callCluster('get', ...)
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._writeToCluster('update', ...)
+        await expectNotFoundError(type, id, [newNs1, newNs2]);
+        expectClusterCalls('get', 'update');
       });
+    });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: 'wait_for',
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        let callAdminClusterCount = 0;
+        migrator.runMigrations = jest.fn(async () =>
+          // runMigrations should resolve before callAdminCluster is initiated
+          expect(callAdminCluster).toHaveBeenCalledTimes(callAdminClusterCount++)
+        );
+        await expect(addToNamespacesSuccess(type, id, [newNs1, newNs2])).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveReturnedTimes(2);
       });
     });
 
-    it('accepts custom refresh settings', async () => {
-      await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          id: 'logstash-*',
-          title: 'Logstash',
-        },
-        {
-          refresh: true,
-        }
-      );
+    describe('returns', () => {
+      it(`returns an empty object on success`, async () => {
+        const result = await addToNamespacesSuccess(type, id, [newNs1, newNs2]);
+        expect(result).toEqual({});
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: true,
+      it(`succeeds when adding existing namespaces`, async () => {
+        const result = await addToNamespacesSuccess(type, id, [currentNs1]);
+        expect(result).toEqual({});
       });
     });
+  });
 
-    it('should use create action if ID defined and overwrite=false', async () => {
-      await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          title: 'Logstash',
-        },
-        {
-          id: 'logstash-*',
-        }
-      );
+  describe('#bulkCreate', () => {
+    const obj1 = {
+      type: 'config',
+      id: '6.0.0-alpha1',
+      attributes: { title: 'Test One' },
+      references: [{ name: 'ref_0', type: 'test', id: '1' }],
+    };
+    const obj2 = {
+      type: 'index-pattern',
+      id: 'logstash-*',
+      attributes: { title: 'Test Two' },
+      references: [{ name: 'ref_0', type: 'test', id: '2' }],
+    };
+    const namespace = 'foo-namespace';
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('create', expect.any(Object));
-    });
+    const getMockBulkCreateResponse = (objects, namespace) => {
+      return {
+        items: objects.map(({ type, id }) => ({
+          create: {
+            _id: `${namespace ? `${namespace}:` : ''}${type}:${id}`,
+            ...mockVersionProps,
+          },
+        })),
+      };
+    };
 
-    it('allows for id to be provided', async () => {
-      await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          title: 'Logstash',
-        },
-        { id: 'logstash-*' }
-      );
+    const bulkCreateSuccess = async (objects, options) => {
+      const multiNamespaceObjects =
+        options?.overwrite &&
+        objects.filter(({ type, id }) => registry.isMultiNamespace(type) && id);
+      if (multiNamespaceObjects?.length) {
+        const response = getMockMgetResponse(multiNamespaceObjects, options?.namespace);
+        callAdminCluster.mockResolvedValueOnce(response); // this._callCluster('mget', ...)
+      }
+      const response = getMockBulkCreateResponse(objects, options?.namespace);
+      callAdminCluster.mockResolvedValue(response); // this._writeToCluster('bulk', ...)
+      const result = await savedObjectsRepository.bulkCreate(objects, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(multiNamespaceObjects?.length ? 2 : 1);
+      return result;
+    };
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: 'index-pattern:logstash-*',
-        })
-      );
+    // bulk create calls have two objects for each source -- the action, and the source
+    const expectClusterCallArgsAction = (
+      objects,
+      { method, _index = expect.any(String), getId = () => expect.any(String) }
+    ) => {
+      const body = [];
+      for (const { type, id } of objects) {
+        body.push({ [method]: { _index, _id: getId(type, id) } });
+        body.push(expect.any(Object));
+      }
+      expectClusterCallArgs({ body });
+    };
+
+    const expectObjArgs = ({ type, attributes, references }, overrides) => [
+      expect.any(Object),
+      expect.objectContaining({
+        [type]: attributes,
+        references,
+        type,
+        ...overrides,
+        ...mockTimestampFields,
+      }),
+    ];
+
+    const expectSuccessResult = obj => ({
+      ...obj,
+      migrationVersion: undefined,
+      version: mockVersion,
+      ...mockTimestampFields,
     });
 
-    it('self-generates an ID', async () => {
-      await savedObjectsRepository.create('index-pattern', {
-        title: 'Logstash',
+    describe('cluster calls', () => {
+      it(`should use the ES bulk action by default`, async () => {
+        await bulkCreateSuccess([obj1, obj2]);
+        expectClusterCalls('bulk');
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: expect.objectContaining(/index-pattern:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}/),
-        })
-      );
-    });
+      it(`should use the ES mget action before bulk action for any types that are multi-namespace, when overwrite=true`, async () => {
+        const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_TYPE }];
+        await bulkCreateSuccess(objects, { overwrite: true });
+        expectClusterCalls('mget', 'bulk');
+        const docs = [expect.objectContaining({ _id: `${MULTI_NAMESPACE_TYPE}:${obj2.id}` })];
+        expectClusterCallArgs({ body: { docs } }, 1);
+      });
 
-    it('prepends namespace to the id and adds namespace to body when providing namespace for namespaced type', async () => {
-      await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          title: 'Logstash',
-        },
-        {
-          id: 'foo-id',
-          namespace: 'foo-namespace',
-        }
-      );
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: `foo-namespace:index-pattern:foo-id`,
-          body: expect.objectContaining({
-            [`index-pattern`]: { title: 'Logstash' },
-            namespace: 'foo-namespace',
-            type: 'index-pattern',
-            updated_at: '2017-08-14T15:49:14.886Z',
-          }),
-        })
-      );
-    });
+      it(`should use the ES create method if ID is undefined and overwrite=true`, async () => {
+        const objects = [obj1, obj2].map(obj => ({ ...obj, id: undefined }));
+        await bulkCreateSuccess(objects, { overwrite: true });
+        expectClusterCallArgsAction(objects, { method: 'create' });
+      });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => {
-      await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          title: 'Logstash',
-        },
-        {
-          id: 'foo-id',
-        }
-      );
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: `index-pattern:foo-id`,
-          body: expect.objectContaining({
-            [`index-pattern`]: { title: 'Logstash' },
-            type: 'index-pattern',
-            updated_at: '2017-08-14T15:49:14.886Z',
-          }),
-        })
-      );
-    });
+      it(`should use the ES create method if ID is undefined and overwrite=false`, async () => {
+        const objects = [obj1, obj2].map(obj => ({ ...obj, id: undefined }));
+        await bulkCreateSuccess(objects);
+        expectClusterCallArgsAction(objects, { method: 'create' });
+      });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => {
-      await savedObjectsRepository.create(
-        'globaltype',
-        {
-          title: 'Logstash',
-        },
-        {
-          id: 'foo-id',
-          namespace: 'foo-namespace',
-        }
-      );
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: `globaltype:foo-id`,
-          body: expect.objectContaining({
-            [`globaltype`]: { title: 'Logstash' },
-            type: 'globaltype',
-            updated_at: '2017-08-14T15:49:14.886Z',
-          }),
-        })
-      );
-    });
-
-    it('defaults to empty references array if none are provided', async () => {
-      await savedObjectsRepository.create(
-        'index-pattern',
-        {
-          title: 'Logstash',
-        },
-        {
-          id: 'logstash-*',
-        }
-      );
+      it(`should use the ES index method if ID is defined and overwrite=true`, async () => {
+        await bulkCreateSuccess([obj1, obj2], { overwrite: true });
+        expectClusterCallArgsAction([obj1, obj2], { method: 'index' });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          body: expect.objectContaining({
-            references: [],
-          }),
-        })
-      );
-    });
-  });
+      it(`should use the ES create method if ID is defined and overwrite=false`, async () => {
+        await bulkCreateSuccess([obj1, obj2]);
+        expectClusterCallArgsAction([obj1, obj2], { method: 'create' });
+      });
 
-  describe('#bulkCreate', () => {
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
-      callAdminCluster.mockReturnValue({
-        items: [
-          { create: { type: 'config', id: 'config:one', _primary_term: 1, _seq_no: 1 } },
-          {
-            create: {
-              type: 'index-pattern',
-              id: 'index-pattern:two',
-              _primary_term: 1,
-              _seq_no: 1,
-            },
-          },
-        ],
+      it(`formats the ES request`, async () => {
+        await bulkCreateSuccess([obj1, obj2]);
+        const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)];
+        expectClusterCallArgs({ body });
       });
 
-      await expect(
-        savedObjectsRepository.bulkCreate([
-          { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-          { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } },
-        ])
-      ).resolves.toBeDefined();
+      it(`adds namespace to request body for any types that are single-namespace`, async () => {
+        await bulkCreateSuccess([obj1, obj2], { namespace });
+        const expected = expect.objectContaining({ namespace });
+        const body = [expect.any(Object), expected, expect.any(Object), expected];
+        expectClusterCallArgs({ body });
+      });
 
-      expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
-    });
+      it(`doesn't add namespace to request body for any types that are not single-namespace`, async () => {
+        const objects = [
+          { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE },
+          { ...obj2, type: MULTI_NAMESPACE_TYPE },
+        ];
+        await bulkCreateSuccess(objects, { namespace });
+        const expected = expect.not.objectContaining({ namespace: expect.anything() });
+        const body = [expect.any(Object), expected, expect.any(Object), expected];
+        expectClusterCallArgs({ body });
+      });
 
-    it('formats Elasticsearch request', async () => {
-      callAdminCluster.mockReturnValue({
-        items: [
-          { create: { type: 'config', id: 'config:one', _primary_term: 1, _seq_no: 1 } },
-          { create: { type: 'index-pattern', id: 'config:two', _primary_term: 1, _seq_no: 1 } },
-        ],
+      it(`adds namespaces to request body for any types that are multi-namespace`, async () => {
+        const test = async namespace => {
+          const objects = [obj1, obj2].map(x => ({ ...x, type: MULTI_NAMESPACE_TYPE }));
+          const namespaces = [namespace ?? 'default'];
+          await bulkCreateSuccess(objects, { namespace, overwrite: true });
+          const expected = expect.objectContaining({ namespaces });
+          const body = [expect.any(Object), expected, expect.any(Object), expected];
+          expectClusterCallArgs({ body }, 2);
+          callAdminCluster.mockReset();
+        };
+        await test(undefined);
+        await test(namespace);
       });
 
-      await savedObjectsRepository.bulkCreate([
-        {
-          type: 'config',
-          id: 'one',
-          attributes: { title: 'Test One' },
-          references: [{ name: 'ref_0', type: 'test', id: '1' }],
-        },
-        {
-          type: 'index-pattern',
-          id: 'two',
-          attributes: { title: 'Test Two' },
-          references: [{ name: 'ref_0', type: 'test', id: '2' }],
-        },
-      ]);
+      it(`doesn't add namespaces to request body for any types that are not multi-namespace`, async () => {
+        const test = async namespace => {
+          const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }];
+          await bulkCreateSuccess(objects, { namespace, overwrite: true });
+          const expected = expect.not.objectContaining({ namespaces: expect.anything() });
+          const body = [expect.any(Object), expected, expect.any(Object), expected];
+          expectClusterCallArgs({ body });
+          callAdminCluster.mockReset();
+        };
+        await test(undefined);
+        await test(namespace);
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      const bulkCalls = callAdminCluster.mock.calls.filter(([path]) => path === 'bulk');
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await bulkCreateSuccess([obj1, obj2]);
+        expectClusterCallArgs({ refresh: 'wait_for' });
+      });
 
-      expect(bulkCalls.length).toEqual(1);
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await bulkCreateSuccess([obj1, obj2], { refresh });
+        expectClusterCallArgs({ refresh });
+      });
 
-      expect(bulkCalls[0][1].body).toEqual([
-        { create: { _index: '.kibana-test', _id: 'config:one' } },
-        {
-          type: 'config',
-          ...mockTimestampFields,
-          config: { title: 'Test One' },
-          references: [{ name: 'ref_0', type: 'test', id: '1' }],
-        },
-        { create: { _index: '.kibana-test', _id: 'index-pattern:two' } },
-        {
-          type: 'index-pattern',
-          ...mockTimestampFields,
-          'index-pattern': { title: 'Test Two' },
-          references: [{ name: 'ref_0', type: 'test', id: '2' }],
-        },
-      ]);
-    });
+      it(`should use default index`, async () => {
+        await bulkCreateSuccess([obj1, obj2]);
+        expectClusterCallArgsAction([obj1, obj2], { method: 'create', _index: '.kibana-test' });
+      });
 
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      callAdminCluster.mockReturnValue({
-        items: [{ create: { type: 'config', id: 'config:one', _primary_term: 1, _seq_no: 1 } }],
+      it(`should use custom index`, async () => {
+        await bulkCreateSuccess([obj1, obj2].map(x => ({ ...x, type: CUSTOM_INDEX_TYPE })));
+        expectClusterCallArgsAction([obj1, obj2], { method: 'create', _index: 'custom' });
       });
 
-      await savedObjectsRepository.bulkCreate([
-        {
-          type: 'config',
-          id: 'one',
-          attributes: { title: 'Test One' },
-          references: [{ name: 'ref_0', type: 'test', id: '1' }],
-        },
-      ]);
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        const getId = (type, id) => `${namespace}:${type}:${id}`;
+        await bulkCreateSuccess([obj1, obj2], { namespace });
+        expectClusterCallArgsAction([obj1, obj2], { method: 'create', getId });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        const getId = (type, id) => `${type}:${id}`;
+        await bulkCreateSuccess([obj1, obj2]);
+        expectClusterCallArgsAction([obj1, obj2], { method: 'create', getId });
+      });
 
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: 'wait_for',
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        const getId = (type, id) => `${type}:${id}`;
+        const objects = [
+          { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE },
+          { ...obj2, type: MULTI_NAMESPACE_TYPE },
+        ];
+        await bulkCreateSuccess(objects, { namespace });
+        expectClusterCallArgsAction(objects, { method: 'create', getId });
       });
     });
 
-    it('accepts a custom refresh setting', async () => {
-      callAdminCluster.mockReturnValue({
-        items: [
-          { create: { type: 'config', id: 'config:one', _primary_term: 1, _seq_no: 1 } },
-          { create: { type: 'index-pattern', id: 'config:two', _primary_term: 1, _seq_no: 1 } },
-        ],
-      });
+    describe('errors', () => {
+      const obj3 = {
+        type: 'dashboard',
+        id: 'three',
+        attributes: { title: 'Test Three' },
+        references: [{ name: 'ref_0', type: 'test', id: '2' }],
+      };
 
-      await savedObjectsRepository.bulkCreate(
-        [
-          {
-            type: 'config',
-            id: 'one',
-            attributes: { title: 'Test One' },
-            references: [{ name: 'ref_0', type: 'test', id: '1' }],
-          },
-          {
-            type: 'index-pattern',
-            id: 'two',
-            attributes: { title: 'Test Two' },
-            references: [{ name: 'ref_0', type: 'test', id: '2' }],
-          },
-        ],
-        {
-          refresh: true,
+      const bulkCreateError = async (obj, esError, expectedError) => {
+        const objects = [obj1, obj, obj2];
+        const response = getMockBulkCreateResponse(objects);
+        if (esError) {
+          response.items[1].create = { error: esError };
         }
-      );
-
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+        callAdminCluster.mockResolvedValue(response); // this._writeToCluster('bulk', ...)
+
+        const result = await savedObjectsRepository.bulkCreate(objects);
+        expectClusterCalls('bulk');
+        const objCall = esError ? expectObjArgs(obj) : [];
+        const body = [...expectObjArgs(obj1), ...objCall, ...expectObjArgs(obj2)];
+        expectClusterCallArgs({ body });
+        expect(result).toEqual({
+          saved_objects: [expectSuccess(obj1), expectedError, expectSuccess(obj2)],
+        });
+      };
 
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: true,
+      it(`returns error when type is invalid`, async () => {
+        const obj = { ...obj3, type: 'unknownType' };
+        await bulkCreateError(obj, undefined, expectErrorInvalidType(obj));
       });
-    });
 
-    it('migrates the docs', async () => {
-      callAdminCluster.mockReturnValue({
-        items: [
-          {
-            create: {
-              error: false,
-              _id: '1',
-              _seq_no: 1,
-              _primary_term: 1,
-            },
-          },
-          {
-            create: {
-              error: false,
-              _id: '2',
-              _seq_no: 1,
-              _primary_term: 1,
-            },
-          },
-        ],
+      it(`returns error when type is hidden`, async () => {
+        const obj = { ...obj3, type: HIDDEN_TYPE };
+        await bulkCreateError(obj, undefined, expectErrorInvalidType(obj));
       });
 
-      migrator.migrateDocument = doc => {
-        doc.attributes.title = doc.attributes.title + '!!';
-        doc.migrationVersion = { foo: '2.3.4' };
-        doc.references = [{ name: 'search_0', type: 'search', id: '123' }];
-        return doc;
-      };
-
-      const bulkCreateResp = await savedObjectsRepository.bulkCreate([
-        { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-        { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } },
-      ]);
-
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'bulk',
-        expect.objectContaining({
-          body: [
-            { create: { _index: '.kibana-test', _id: 'config:one' } },
-            {
-              type: 'config',
-              ...mockTimestampFields,
-              config: { title: 'Test One!!' },
-              migrationVersion: { foo: '2.3.4' },
-              references: [{ name: 'search_0', type: 'search', id: '123' }],
-            },
-            { create: { _index: '.kibana-test', _id: 'index-pattern:two' } },
+      it(`returns error when there is a conflict with an existing multi-namespace saved object (get)`, async () => {
+        const obj = { ...obj3, type: MULTI_NAMESPACE_TYPE };
+        const response1 = {
+          status: 200,
+          docs: [
             {
-              type: 'index-pattern',
-              ...mockTimestampFields,
-              'index-pattern': { title: 'Test Two!!' },
-              migrationVersion: { foo: '2.3.4' },
-              references: [{ name: 'search_0', type: 'search', id: '123' }],
+              found: true,
+              _source: {
+                type: obj.type,
+                namespaces: ['bar-namespace'],
+              },
             },
           ],
-        })
-      );
-
-      expect(bulkCreateResp).toEqual({
-        saved_objects: [
-          {
-            id: 'one',
-            type: 'config',
-            version: mockVersion,
-            updated_at: mockTimestamp,
-            attributes: {
-              title: 'Test One!!',
-            },
-            references: [{ name: 'search_0', type: 'search', id: '123' }],
-          },
-          {
-            id: 'two',
-            type: 'index-pattern',
-            version: mockVersion,
-            updated_at: mockTimestamp,
-            attributes: {
-              title: 'Test Two!!',
-            },
-            references: [{ name: 'search_0', type: 'search', id: '123' }],
-          },
-        ],
+        };
+        callAdminCluster.mockResolvedValueOnce(response1); // this._callCluster('mget', ...)
+        const response2 = getMockBulkCreateResponse([obj1, obj2]);
+        callAdminCluster.mockResolvedValue(response2); // this._writeToCluster('bulk', ...)
+
+        const options = { overwrite: true };
+        const result = await savedObjectsRepository.bulkCreate([obj1, obj, obj2], options);
+        expectClusterCalls('mget', 'bulk');
+        const body1 = { docs: [expect.objectContaining({ _id: `${obj.type}:${obj.id}` })] };
+        expectClusterCallArgs({ body: body1 }, 1);
+        const body2 = [...expectObjArgs(obj1), ...expectObjArgs(obj2)];
+        expectClusterCallArgs({ body: body2 }, 2);
+        expect(result).toEqual({
+          saved_objects: [expectSuccess(obj1), expectErrorConflict(obj), expectSuccess(obj2)],
+        });
       });
-    });
 
-    it('should overwrite objects if overwrite is truthy', async () => {
-      callAdminCluster.mockReturnValue({
-        items: [{ create: { type: 'foo', id: 'bar', _primary_term: 1, _seq_no: 1 } }],
+      it(`returns error when there is a version conflict (bulk)`, async () => {
+        const esError = { type: 'version_conflict_engine_exception' };
+        await bulkCreateError(obj3, esError, expectErrorConflict(obj3));
       });
 
-      await savedObjectsRepository.bulkCreate([{ type: 'foo', id: 'bar', attributes: {} }], {
-        overwrite: false,
+      it(`returns error when document is missing`, async () => {
+        const esError = { type: 'document_missing_exception' };
+        await bulkCreateError(obj3, esError, expectErrorNotFound(obj3));
       });
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'bulk',
-        expect.objectContaining({
-          body: [
-            // uses create because overwriting is not allowed
-            { create: { _index: '.kibana-test', _id: 'foo:bar' } },
-            { type: 'foo', ...mockTimestampFields, foo: {}, references: [] },
-          ],
-        })
-      );
-
-      callAdminCluster.mockReset();
 
-      callAdminCluster.mockReturnValue({
-        items: [{ create: { type: 'foo', id: 'bar', _primary_term: 1, _seq_no: 1 } }],
+      it(`returns error reason for other errors`, async () => {
+        const esError = { reason: 'some_other_error' };
+        await bulkCreateError(obj3, esError, expectErrorResult(obj3, { message: esError.reason }));
       });
 
-      await savedObjectsRepository.bulkCreate([{ type: 'foo', id: 'bar', attributes: {} }], {
-        overwrite: true,
+      it(`returns error string for other errors if no reason is defined`, async () => {
+        const esError = { foo: 'some_other_error' };
+        const expectedError = expectErrorResult(obj3, { message: JSON.stringify(esError) });
+        await bulkCreateError(obj3, esError, expectedError);
       });
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'bulk',
-        expect.objectContaining({
-          body: [
-            // uses index because overwriting is allowed
-            { index: { _index: '.kibana-test', _id: 'foo:bar' } },
-            { type: 'foo', ...mockTimestampFields, foo: {}, references: [] },
-          ],
-        })
-      );
     });
 
-    it('mockReturnValue document errors', async () => {
-      callAdminCluster.mockResolvedValue({
-        errors: false,
-        items: [
-          {
-            create: {
-              _id: 'config:one',
-              error: {
-                reason: 'type[config] missing',
-              },
-            },
-          },
-          {
-            create: {
-              _id: 'index-pattern:two',
-              ...mockVersionProps,
-            },
-          },
-        ],
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(bulkCreateSuccess([obj1, obj2])).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
       });
 
-      const response = await savedObjectsRepository.bulkCreate([
-        { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-        { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } },
-      ]);
+      it(`migrates the docs and serializes the migrated docs`, async () => {
+        migrator.migrateDocument.mockImplementation(mockMigrateDocument);
+        await bulkCreateSuccess([obj1, obj2]);
+        const docs = [obj1, obj2].map(x => ({ ...x, ...mockTimestampFields }));
+        expectMigrationArgs(docs[0], true, 1);
+        expectMigrationArgs(docs[1], true, 2);
 
-      expect(response).toEqual({
-        saved_objects: [
-          {
-            id: 'one',
-            type: 'config',
-            error: { message: 'type[config] missing' },
-          },
-          {
-            id: 'two',
-            type: 'index-pattern',
-            version: mockVersion,
-            ...mockTimestampFields,
-            attributes: { title: 'Test Two' },
-            references: [],
-          },
-        ],
+        const migratedDocs = docs.map(x => migrator.migrateDocument(x));
+        expect(serializer.savedObjectToRaw).toHaveBeenNthCalledWith(1, migratedDocs[0]);
+        expect(serializer.savedObjectToRaw).toHaveBeenNthCalledWith(2, migratedDocs[1]);
       });
-    });
 
-    it('formats Elasticsearch response', async () => {
-      callAdminCluster.mockResolvedValue({
-        errors: false,
-        items: [
-          {
-            create: {
-              _id: 'config:one',
-              ...mockVersionProps,
-            },
-          },
-          {
-            create: {
-              _id: 'index-pattern:two',
-              ...mockVersionProps,
-            },
-          },
-        ],
+      it(`adds namespace to body when providing namespace for single-namespace type`, async () => {
+        await bulkCreateSuccess([obj1, obj2], { namespace });
+        expectMigrationArgs({ namespace }, true, 1);
+        expectMigrationArgs({ namespace }, true, 2);
       });
 
-      const response = await savedObjectsRepository.bulkCreate(
-        [
-          { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-          { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } },
-        ],
-        {
-          namespace: 'foo-namespace',
-        }
-      );
+      it(`doesn't add namespace to body when providing no namespace for single-namespace type`, async () => {
+        await bulkCreateSuccess([obj1, obj2]);
+        expectMigrationArgs({ namespace: expect.anything() }, false, 1);
+        expectMigrationArgs({ namespace: expect.anything() }, false, 2);
+      });
 
-      expect(response).toEqual({
-        saved_objects: [
-          {
-            id: 'one',
-            type: 'config',
-            version: mockVersion,
-            ...mockTimestampFields,
-            attributes: { title: 'Test One' },
-            references: [],
-          },
-          {
-            id: 'two',
-            type: 'index-pattern',
-            version: mockVersion,
-            ...mockTimestampFields,
-            attributes: { title: 'Test Two' },
-            references: [],
-          },
-        ],
+      it(`doesn't add namespace to body when not using single-namespace type`, async () => {
+        const objects = [
+          { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE },
+          { ...obj2, type: MULTI_NAMESPACE_TYPE },
+        ];
+        await bulkCreateSuccess(objects, { namespace });
+        expectMigrationArgs({ namespace: expect.anything() }, false, 1);
+        expectMigrationArgs({ namespace: expect.anything() }, false, 2);
       });
-    });
 
-    it('prepends namespace to the id and adds namespace to body when providing namespace for namespaced type', async () => {
-      callAdminCluster.mockReturnValue({
-        items: [
-          {
-            create: {
-              _id: 'foo-namespace:config:one',
-              _index: '.kibana-test',
-              _primary_term: 1,
-              _seq_no: 2,
-            },
-          },
-          {
-            create: {
-              _id: 'foo-namespace:index-pattern:two',
-              _primary_term: 1,
-              _seq_no: 2,
-            },
-          },
-        ],
+      it(`adds namespaces to body when providing namespace for multi-namespace type`, async () => {
+        const objects = [obj1, obj2].map(obj => ({ ...obj, type: MULTI_NAMESPACE_TYPE }));
+        await bulkCreateSuccess(objects, { namespace });
+        expectMigrationArgs({ namespaces: [namespace] }, true, 1);
+        expectMigrationArgs({ namespaces: [namespace] }, true, 2);
       });
-      await savedObjectsRepository.bulkCreate(
-        [
-          { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-          { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } },
-        ],
-        {
-          namespace: 'foo-namespace',
-        }
-      );
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'bulk',
-        expect.objectContaining({
-          body: [
-            { create: { _index: '.kibana-test', _id: 'foo-namespace:config:one' } },
-            {
-              namespace: 'foo-namespace',
-              type: 'config',
-              ...mockTimestampFields,
-              config: { title: 'Test One' },
-              references: [],
-            },
-            { create: { _index: '.kibana-test', _id: 'foo-namespace:index-pattern:two' } },
-            {
-              namespace: 'foo-namespace',
-              type: 'index-pattern',
-              ...mockTimestampFields,
-              'index-pattern': { title: 'Test Two' },
-              references: [],
-            },
-          ],
-        })
-      );
-    });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => {
-      callAdminCluster.mockResolvedValue({
-        errors: false,
-        items: [
-          {
-            create: {
-              _id: 'config:one',
-              ...mockVersionProps,
-            },
-          },
-          {
-            create: {
-              _id: 'index-pattern:two',
-              ...mockVersionProps,
-            },
-          },
-        ],
+      it(`adds default namespaces to body when providing no namespace for multi-namespace type`, async () => {
+        const objects = [obj1, obj2].map(obj => ({ ...obj, type: MULTI_NAMESPACE_TYPE }));
+        await bulkCreateSuccess(objects);
+        expectMigrationArgs({ namespaces: ['default'] }, true, 1);
+        expectMigrationArgs({ namespaces: ['default'] }, true, 2);
       });
-      await savedObjectsRepository.bulkCreate([
-        { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-        { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } },
-      ]);
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'bulk',
-        expect.objectContaining({
-          body: [
-            { create: { _id: 'config:one', _index: '.kibana-test' } },
-            {
-              type: 'config',
-              ...mockTimestampFields,
-              config: { title: 'Test One' },
-              references: [],
-            },
-            { create: { _id: 'index-pattern:two', _index: '.kibana-test' } },
-            {
-              type: 'index-pattern',
-              ...mockTimestampFields,
-              'index-pattern': { title: 'Test Two' },
-              references: [],
-            },
-          ],
-        })
-      );
-    });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => {
-      callAdminCluster.mockReturnValue({
-        items: [{ create: { _type: '_doc', _id: 'globaltype:one', _primary_term: 1, _seq_no: 2 } }],
+      it(`doesn't add namespaces to body when not using multi-namespace type`, async () => {
+        const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }];
+        await bulkCreateSuccess(objects);
+        expectMigrationArgs({ namespaces: expect.anything() }, false, 1);
+        expectMigrationArgs({ namespaces: expect.anything() }, false, 2);
       });
-      await savedObjectsRepository.bulkCreate(
-        [{ type: 'globaltype', id: 'one', attributes: { title: 'Test One' } }],
-        {
-          namespace: 'foo-namespace',
-        }
-      );
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'bulk',
-        expect.objectContaining({
-          body: [
-            { create: { _id: 'globaltype:one', _index: '.kibana-test' } },
-            {
-              type: 'globaltype',
-              ...mockTimestampFields,
-              globaltype: { title: 'Test One' },
-              references: [],
-            },
-          ],
-        })
-      );
     });
 
-    it('should return objects in the same order regardless of type', () => {});
-  });
+    describe('returns', () => {
+      it(`formats the ES response`, async () => {
+        const result = await bulkCreateSuccess([obj1, obj2]);
+        expect(result).toEqual({
+          saved_objects: [obj1, obj2].map(x => expectSuccessResult(x)),
+        });
+      });
 
-  describe('#delete', () => {
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
-      callAdminCluster.mockReturnValue({ result: 'deleted' });
-      await expect(
-        savedObjectsRepository.delete('index-pattern', 'logstash-*', {
-          namespace: 'foo-namespace',
-        })
-      ).resolves.toBeDefined();
-
-      expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
+      it(`should return objects in the same order regardless of type`, async () => {
+        // TODO
+      });
+
+      it(`handles a mix of successful creates and errors`, async () => {
+        const obj = {
+          type: 'unknownType',
+          id: 'three',
+        };
+        const objects = [obj1, obj, obj2];
+        const response = getMockBulkCreateResponse(objects);
+        callAdminCluster.mockResolvedValue(response); // this._writeToCluster('bulk', ...)
+        const result = await savedObjectsRepository.bulkCreate(objects);
+        expect(callAdminCluster).toHaveBeenCalledTimes(1);
+        expect(result).toEqual({
+          saved_objects: [expectSuccessResult(obj1), expectError(obj), expectSuccessResult(obj2)],
+        });
+      });
     });
+  });
 
-    it('throws notFound when ES is unable to find the document', async () => {
-      expect.assertions(1);
+  describe('#bulkGet', () => {
+    const obj1 = {
+      type: 'config',
+      id: '6.0.0-alpha1',
+      attributes: { title: 'Testing' },
+      references: [
+        {
+          name: 'ref_0',
+          type: 'test',
+          id: '1',
+        },
+      ],
+    };
+    const obj2 = {
+      type: 'index-pattern',
+      id: 'logstash-*',
+      attributes: { title: 'Testing' },
+      references: [
+        {
+          name: 'ref_0',
+          type: 'test',
+          id: '2',
+        },
+      ],
+    };
+    const namespace = 'foo-namespace';
 
-      callAdminCluster.mockResolvedValue({ result: 'not_found' });
+    const bulkGet = async (objects, options) =>
+      savedObjectsRepository.bulkGet(
+        objects.map(({ type, id }) => ({ type, id })), // bulkGet only uses type and id
+        options
+      );
+    const bulkGetSuccess = async (objects, options) => {
+      const response = getMockMgetResponse(objects, options?.namespace);
+      callAdminCluster.mockReturnValue(response);
+      const result = await bulkGet(objects, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      return result;
+    };
 
-      try {
-        await savedObjectsRepository.delete('index-pattern', 'logstash-*');
-      } catch (e) {
-        expect(e.output.statusCode).toEqual(404);
-      }
-    });
+    const _expectClusterCallArgs = (
+      objects,
+      { _index = expect.any(String), getId = () => expect.any(String) }
+    ) => {
+      expectClusterCallArgs({
+        body: {
+          docs: objects.map(({ type, id }) =>
+            expect.objectContaining({
+              _index,
+              _id: getId(type, id),
+            })
+          ),
+        },
+      });
+    };
 
-    it(`prepends namespace to the id when providing namespace for namespaced type`, async () => {
-      callAdminCluster.mockReturnValue({ result: 'deleted' });
-      await savedObjectsRepository.delete('index-pattern', 'logstash-*', {
-        namespace: 'foo-namespace',
+    describe('cluster calls', () => {
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        const getId = (type, id) => `${namespace}:${type}:${id}`;
+        await bulkGetSuccess([obj1, obj2], { namespace });
+        _expectClusterCallArgs([obj1, obj2], { getId });
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('delete', {
-        id: 'foo-namespace:index-pattern:logstash-*',
-        refresh: 'wait_for',
-        index: '.kibana-test',
-        ignore: [404],
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        const getId = (type, id) => `${type}:${id}`;
+        await bulkGetSuccess([obj1, obj2]);
+        _expectClusterCallArgs([obj1, obj2], { getId });
       });
-    });
 
-    it(`doesn't prepend namespace to the id when providing no namespace for namespaced type`, async () => {
-      callAdminCluster.mockReturnValue({ result: 'deleted' });
-      await savedObjectsRepository.delete('index-pattern', 'logstash-*');
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        const getId = (type, id) => `${type}:${id}`;
+        let objects = [obj1, obj2].map(obj => ({ ...obj, type: NAMESPACE_AGNOSTIC_TYPE }));
+        await bulkGetSuccess(objects, { namespace });
+        _expectClusterCallArgs(objects, { getId });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('delete', {
-        id: 'index-pattern:logstash-*',
-        refresh: 'wait_for',
-        index: '.kibana-test',
-        ignore: [404],
+        callAdminCluster.mockReset();
+        objects = [obj1, obj2].map(obj => ({ ...obj, type: MULTI_NAMESPACE_TYPE }));
+        await bulkGetSuccess(objects, { namespace });
+        _expectClusterCallArgs(objects, { getId });
       });
     });
 
-    it(`doesn't prepend namespace to the id when providing namespace for namespace agnostic type`, async () => {
-      callAdminCluster.mockReturnValue({ result: 'deleted' });
-      await savedObjectsRepository.delete('globaltype', 'logstash-*', {
-        namespace: 'foo-namespace',
-      });
+    describe('errors', () => {
+      const bulkGetErrorInvalidType = async ([obj1, obj, obj2]) => {
+        const response = getMockMgetResponse([obj1, obj2]);
+        callAdminCluster.mockResolvedValue(response);
+        const result = await bulkGet([obj1, obj, obj2]);
+        expectClusterCalls('mget');
+        expect(result).toEqual({
+          saved_objects: [expectSuccess(obj1), expectErrorInvalidType(obj), expectSuccess(obj2)],
+        });
+      };
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('delete', {
-        id: 'globaltype:logstash-*',
-        refresh: 'wait_for',
-        index: '.kibana-test',
-        ignore: [404],
-      });
-    });
+      const bulkGetErrorNotFound = async ([obj1, obj, obj2], options, response) => {
+        callAdminCluster.mockResolvedValue(response);
+        const result = await bulkGet([obj1, obj, obj2], options);
+        expectClusterCalls('mget');
+        expect(result).toEqual({
+          saved_objects: [expectSuccess(obj1), expectErrorNotFound(obj), expectSuccess(obj2)],
+        });
+      };
 
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      callAdminCluster.mockReturnValue({ result: 'deleted' });
-      await savedObjectsRepository.delete('globaltype', 'logstash-*');
+      it(`returns error when type is invalid`, async () => {
+        const obj = { type: 'unknownType', id: 'three' };
+        await bulkGetErrorInvalidType([obj1, obj, obj2]);
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: 'wait_for',
+      it(`returns error when type is hidden`, async () => {
+        const obj = { type: HIDDEN_TYPE, id: 'three' };
+        await bulkGetErrorInvalidType([obj1, obj, obj2]);
       });
-    });
 
-    it(`accepts a custom refresh setting`, async () => {
-      callAdminCluster.mockReturnValue({ result: 'deleted' });
-      await savedObjectsRepository.delete('globaltype', 'logstash-*', {
-        refresh: false,
+      it(`returns error when document is not found`, async () => {
+        const obj = { type: 'dashboard', id: 'three', found: false };
+        const response = getMockMgetResponse([obj1, obj, obj2]);
+        await bulkGetErrorNotFound([obj1, obj, obj2], undefined, response);
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: false,
+      it(`handles missing ids gracefully`, async () => {
+        const obj = { type: 'dashboard', id: undefined, found: false };
+        const response = getMockMgetResponse([obj1, obj, obj2]);
+        await bulkGetErrorNotFound([obj1, obj, obj2], undefined, response);
       });
-    });
-  });
 
-  describe('#deleteByNamespace', () => {
-    it('requires namespace to be defined', async () => {
-      callAdminCluster.mockReturnValue(deleteByQueryResults);
-      expect(savedObjectsRepository.deleteByNamespace()).rejects.toThrowErrorMatchingSnapshot();
-      expect(callAdminCluster).not.toHaveBeenCalled();
+      it(`returns error when type is multi-namespace and the document exists, but not in this namespace`, async () => {
+        const obj = { type: MULTI_NAMESPACE_TYPE, id: 'three' };
+        const response = getMockMgetResponse([obj1, obj, obj2]);
+        response.docs[1].namespaces = ['bar-namespace'];
+        await bulkGetErrorNotFound([obj1, obj, obj2], { namespace }, response);
+      });
     });
 
-    it('requires namespace to be a string', async () => {
-      callAdminCluster.mockReturnValue(deleteByQueryResults);
-      expect(
-        savedObjectsRepository.deleteByNamespace(['namespace-1', 'namespace-2'])
-      ).rejects.toThrowErrorMatchingSnapshot();
-      expect(callAdminCluster).not.toHaveBeenCalled();
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(bulkGetSuccess([obj1, obj2])).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
+      });
     });
 
-    it('constructs a deleteByQuery call using all types that are namespace aware', async () => {
-      callAdminCluster.mockReturnValue(deleteByQueryResults);
-      const result = await savedObjectsRepository.deleteByNamespace('my-namespace');
-
-      expect(result).toEqual(deleteByQueryResults);
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-
-      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, typeRegistry, {
-        namespace: 'my-namespace',
-        type: ['config', 'baz', 'index-pattern', 'dashboard'],
+    describe('returns', () => {
+      const expectSuccessResult = ({ type, id }, doc) => ({
+        type,
+        id,
+        ...(doc._source.namespaces && { namespaces: doc._source.namespaces }),
+        ...(doc._source.updated_at && { updated_at: doc._source.updated_at }),
+        version: encodeHitVersion(doc),
+        attributes: doc._source[type],
+        references: doc._source.references || [],
+        migrationVersion: doc._source.migrationVersion,
       });
 
-      expect(callAdminCluster).toHaveBeenCalledWith('deleteByQuery', {
-        body: { conflicts: 'proceed' },
-        ignore: [404],
-        index: ['.kibana-test', 'beats'],
-        refresh: 'wait_for',
+      it(`returns early for empty objects argument`, async () => {
+        const result = await bulkGet([]);
+        expect(result).toEqual({ saved_objects: [] });
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
-    });
-
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      callAdminCluster.mockReturnValue(deleteByQueryResults);
-      await savedObjectsRepository.deleteByNamespace('my-namespace');
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: 'wait_for',
+      it(`formats the ES response`, async () => {
+        const response = getMockMgetResponse([obj1, obj2]);
+        callAdminCluster.mockResolvedValue(response);
+        const result = await bulkGet([obj1, obj2]);
+        expect(callAdminCluster).toHaveBeenCalledTimes(1);
+        expect(result).toEqual({
+          saved_objects: [
+            expectSuccessResult(obj1, response.docs[0]),
+            expectSuccessResult(obj2, response.docs[1]),
+          ],
+        });
       });
-    });
 
-    it('accepts a custom refresh setting', async () => {
-      callAdminCluster.mockReturnValue(deleteByQueryResults);
-      await savedObjectsRepository.deleteByNamespace('my-namespace', { refresh: true });
+      it(`handles a mix of successful gets and errors`, async () => {
+        const response = getMockMgetResponse([obj1, obj2]);
+        callAdminCluster.mockResolvedValue(response);
+        const obj = { type: 'unknownType', id: 'three' };
+        const result = await bulkGet([obj1, obj, obj2]);
+        expect(callAdminCluster).toHaveBeenCalledTimes(1);
+        expect(result).toEqual({
+          saved_objects: [
+            expectSuccessResult(obj1, response.docs[0]),
+            expectError(obj),
+            expectSuccessResult(obj2, response.docs[1]),
+          ],
+        });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: true,
+      it(`includes namespaces property for multi-namespace documents`, async () => {
+        const obj = { type: MULTI_NAMESPACE_TYPE, id: 'three' };
+        const result = await bulkGetSuccess([obj1, obj]);
+        expect(result).toEqual({
+          saved_objects: [
+            expect.not.objectContaining({ namespaces: expect.anything() }),
+            expect.objectContaining({ namespaces: expect.any(Array) }),
+          ],
+        });
       });
     });
   });
 
-  describe('#find', () => {
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
-
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      await expect(savedObjectsRepository.find({ type: 'foo' })).resolves.toBeDefined();
-
-      expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
-    });
-
-    it('requires type to be defined', async () => {
-      await expect(savedObjectsRepository.find({})).rejects.toThrow(/options\.type must be/);
-      expect(callAdminCluster).not.toHaveBeenCalled();
+  describe('#bulkUpdate', () => {
+    const obj1 = {
+      type: 'config',
+      id: '6.0.0-alpha1',
+      attributes: { title: 'Test One' },
+    };
+    const obj2 = {
+      type: 'index-pattern',
+      id: 'logstash-*',
+      attributes: { title: 'Test Two' },
+    };
+    const references = [{ name: 'ref_0', type: 'test', id: '1' }];
+    const namespace = 'foo-namespace';
+
+    const getMockBulkUpdateResponse = (objects, options) => ({
+      items: objects.map(({ type, id }) => ({
+        update: {
+          _id: `${
+            registry.isSingleNamespace(type) && options?.namespace ? `${options?.namespace}:` : ''
+          }${type}:${id}`,
+          ...mockVersionProps,
+          result: 'updated',
+        },
+      })),
     });
 
-    it('requires searchFields be an array if defined', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      try {
-        await savedObjectsRepository.find({ type: 'foo', searchFields: 'string' });
-        throw new Error('expected find() to reject');
-      } catch (error) {
-        expect(callAdminCluster).not.toHaveBeenCalled();
-        expect(error.message).toMatch('must be an array');
+    const bulkUpdateSuccess = async (objects, options) => {
+      const multiNamespaceObjects = objects.filter(({ type }) => registry.isMultiNamespace(type));
+      if (multiNamespaceObjects?.length) {
+        const response = getMockMgetResponse(multiNamespaceObjects, options?.namespace);
+        callAdminCluster.mockResolvedValueOnce(response); // this._callCluster('mget', ...)
       }
-    });
+      const response = getMockBulkUpdateResponse(objects, options?.namespace);
+      callAdminCluster.mockResolvedValue(response); // this._writeToCluster('bulk', ...)
+      const result = await savedObjectsRepository.bulkUpdate(objects, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(multiNamespaceObjects?.length ? 2 : 1);
+      return result;
+    };
 
-    it('requires fields be an array if defined', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      try {
-        await savedObjectsRepository.find({ type: 'foo', fields: 'string' });
-        throw new Error('expected find() to reject');
-      } catch (error) {
-        expect(callAdminCluster).not.toHaveBeenCalled();
-        expect(error.message).toMatch('must be an array');
+    // bulk create calls have two objects for each source -- the action, and the source
+    const expectClusterCallArgsAction = (
+      objects,
+      { method, _index = expect.any(String), getId = () => expect.any(String), overrides },
+      n
+    ) => {
+      const body = [];
+      for (const { type, id } of objects) {
+        body.push({
+          [method]: {
+            _index,
+            _id: getId(type, id),
+            ...overrides,
+          },
+        });
+        body.push(expect.any(Object));
       }
-    });
-
-    it('passes mappings, schema, search, defaultSearchOperator, searchFields, type, sortField, sortOrder and hasReference to getSearchDsl', async () => {
-      callAdminCluster.mockReturnValue(namespacedSearchResults);
-      const relevantOpts = {
-        namespace: 'foo-namespace',
-        search: 'foo*',
-        searchFields: ['foo'],
-        type: ['bar'],
-        sortField: 'name',
-        sortOrder: 'desc',
-        defaultSearchOperator: 'AND',
-        hasReference: {
-          type: 'foo',
-          id: '1',
-        },
-        kueryNode: undefined,
-      };
+      expectClusterCallArgs({ body }, n);
+    };
 
-      await savedObjectsRepository.find(relevantOpts);
-      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1);
-      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(
-        mappings,
-        typeRegistry,
-        relevantOpts
-      );
-    });
+    const expectObjArgs = ({ type, attributes }) => [
+      expect.any(Object),
+      {
+        doc: expect.objectContaining({
+          [type]: attributes,
+          ...mockTimestampFields,
+        }),
+      },
+    ];
 
-    it('accepts KQL filter and passes keuryNode to getSearchDsl', async () => {
-      callAdminCluster.mockReturnValue(namespacedSearchResults);
-      const findOpts = {
-        namespace: 'foo-namespace',
-        search: 'foo*',
-        searchFields: ['foo'],
-        type: ['dashboard'],
-        sortField: 'name',
-        sortOrder: 'desc',
-        defaultSearchOperator: 'AND',
-        hasReference: {
-          type: 'foo',
-          id: '1',
-        },
-        indexPattern: undefined,
-        filter: 'dashboard.attributes.otherField: *',
+    describe('cluster calls', () => {
+      it(`should use the ES bulk action by default`, async () => {
+        await bulkUpdateSuccess([obj1, obj2]);
+        expectClusterCalls('bulk');
+      });
+
+      it(`should use the ES mget action before bulk action for any types that are multi-namespace`, async () => {
+        const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_TYPE }];
+        await bulkUpdateSuccess(objects);
+        expectClusterCalls('mget', 'bulk');
+        const docs = [expect.objectContaining({ _id: `${MULTI_NAMESPACE_TYPE}:${obj2.id}` })];
+        expectClusterCallArgs({ body: { docs } }, 1);
+      });
+
+      it(`formats the ES request`, async () => {
+        await bulkUpdateSuccess([obj1, obj2]);
+        const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)];
+        expectClusterCallArgs({ body });
+      });
+
+      it(`formats the ES request for any types that are multi-namespace`, async () => {
+        const _obj2 = { ...obj2, type: MULTI_NAMESPACE_TYPE };
+        await bulkUpdateSuccess([obj1, _obj2]);
+        const body = [...expectObjArgs(obj1), ...expectObjArgs(_obj2)];
+        expectClusterCallArgs({ body }, 2);
+      });
+
+      it(`doesnt call Elasticsearch if there are no valid objects to update`, async () => {
+        const objects = [obj1, obj2].map(x => ({ ...x, type: 'unknownType' }));
+        await savedObjectsRepository.bulkUpdate(objects);
+        expect(callAdminCluster).toHaveBeenCalledTimes(0);
+      });
+
+      it(`defaults to no references`, async () => {
+        await bulkUpdateSuccess([obj1, obj2]);
+        const expected = { doc: expect.not.objectContaining({ references: expect.anything() }) };
+        const body = [expect.any(Object), expected, expect.any(Object), expected];
+        expectClusterCallArgs({ body });
+      });
+
+      it(`accepts custom references array`, async () => {
+        const test = async references => {
+          const objects = [obj1, obj2].map(obj => ({ ...obj, references }));
+          await bulkUpdateSuccess(objects);
+          const expected = { doc: expect.objectContaining({ references }) };
+          const body = [expect.any(Object), expected, expect.any(Object), expected];
+          expectClusterCallArgs({ body });
+          callAdminCluster.mockReset();
+        };
+        await test(references);
+        await test(['string']);
+        await test([]);
+      });
+
+      it(`doesn't accept custom references if not an array`, async () => {
+        const test = async references => {
+          const objects = [obj1, obj2].map(obj => ({ ...obj, references }));
+          await bulkUpdateSuccess(objects);
+          const expected = { doc: expect.not.objectContaining({ references: expect.anything() }) };
+          const body = [expect.any(Object), expected, expect.any(Object), expected];
+          expectClusterCallArgs({ body });
+          callAdminCluster.mockReset();
+        };
+        await test('string');
+        await test(123);
+        await test(true);
+        await test(null);
+      });
+
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await bulkUpdateSuccess([obj1, obj2]);
+        expectClusterCallArgs({ refresh: 'wait_for' });
+      });
+
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await bulkUpdateSuccess([obj1, obj2], { refresh });
+        expectClusterCallArgs({ refresh });
+      });
+
+      it(`defaults to the version of the existing document for multi-namespace types`, async () => {
+        // only multi-namespace documents are obtained using a pre-flight mget request
+        const objects = [
+          { ...obj1, type: MULTI_NAMESPACE_TYPE },
+          { ...obj2, type: MULTI_NAMESPACE_TYPE },
+        ];
+        await bulkUpdateSuccess(objects);
+        const overrides = {
+          if_seq_no: mockVersionProps._seq_no,
+          if_primary_term: mockVersionProps._primary_term,
+        };
+        expectClusterCallArgsAction(objects, { method: 'update', overrides }, 2);
+      });
+
+      it(`defaults to no version for types that are not multi-namespace`, async () => {
+        const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }];
+        await bulkUpdateSuccess(objects);
+        expectClusterCallArgsAction(objects, { method: 'update' });
+      });
+
+      it(`accepts version`, async () => {
+        const version = encodeHitVersion({ _seq_no: 100, _primary_term: 200 });
+        // test with both non-multi-namespace and multi-namespace types
+        const objects = [
+          { ...obj1, version },
+          { ...obj2, type: MULTI_NAMESPACE_TYPE, version },
+        ];
+        await bulkUpdateSuccess(objects);
+        const overrides = { if_seq_no: 100, if_primary_term: 200 };
+        expectClusterCallArgsAction(objects, { method: 'update', overrides }, 2);
+      });
+
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        const getId = (type, id) => `${namespace}:${type}:${id}`;
+        await bulkUpdateSuccess([obj1, obj2], { namespace });
+        expectClusterCallArgsAction([obj1, obj2], { method: 'update', getId });
+      });
+
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        const getId = (type, id) => `${type}:${id}`;
+        await bulkUpdateSuccess([obj1, obj2]);
+        expectClusterCallArgsAction([obj1, obj2], { method: 'update', getId });
+      });
+
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        const getId = (type, id) => `${type}:${id}`;
+        const objects1 = [{ ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }];
+        await bulkUpdateSuccess(objects1, { namespace });
+        expectClusterCallArgsAction(objects1, { method: 'update', getId });
+        callAdminCluster.mockReset();
+        const overrides = {
+          // bulkUpdate uses a preflight `get` request for multi-namespace saved objects, and specifies that version on `update`
+          // we aren't testing for this here, but we need to include Jest assertions so this test doesn't fail
+          if_primary_term: expect.any(Number),
+          if_seq_no: expect.any(Number),
+        };
+        const objects2 = [{ ...obj2, type: MULTI_NAMESPACE_TYPE }];
+        await bulkUpdateSuccess(objects2, { namespace });
+        expectClusterCallArgsAction(objects2, { method: 'update', getId, overrides }, 2);
+      });
+    });
+
+    describe('errors', () => {
+      const obj = {
+        type: 'dashboard',
+        id: 'three',
       };
 
-      await savedObjectsRepository.find(findOpts);
-      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1);
-      const { kueryNode } = getSearchDslNS.getSearchDsl.mock.calls[0][2];
-      expect(kueryNode).toMatchInlineSnapshot(`
-        Object {
-          "arguments": Array [
-            Object {
-              "type": "literal",
-              "value": "dashboard.otherField",
-            },
-            Object {
-              "type": "wildcard",
-              "value": "@kuery-wildcard@",
-            },
-            Object {
-              "type": "literal",
-              "value": false,
-            },
-          ],
-          "function": "is",
-          "type": "function",
+      const bulkUpdateError = async (obj, esError, expectedError) => {
+        const objects = [obj1, obj, obj2];
+        const mockResponse = getMockBulkUpdateResponse(objects);
+        if (esError) {
+          mockResponse.items[1].update = { error: esError };
         }
-      `);
-    });
+        callAdminCluster.mockResolvedValue(mockResponse); // this._writeToCluster('bulk', ...)
+
+        const result = await savedObjectsRepository.bulkUpdate(objects);
+        expectClusterCalls('bulk');
+        const objCall = esError ? expectObjArgs(obj) : [];
+        const body = [...expectObjArgs(obj1), ...objCall, ...expectObjArgs(obj2)];
+        expectClusterCallArgs({ body });
+        expect(result).toEqual({
+          saved_objects: [expectSuccess(obj1), expectedError, expectSuccess(obj2)],
+        });
+      };
 
-    it('KQL filter syntax errors rejects with bad request', async () => {
-      callAdminCluster.mockReturnValue(namespacedSearchResults);
-      const findOpts = {
-        namespace: 'foo-namespace',
-        search: 'foo*',
-        searchFields: ['foo'],
-        type: ['dashboard'],
-        sortField: 'name',
-        sortOrder: 'desc',
-        defaultSearchOperator: 'AND',
-        hasReference: {
-          type: 'foo',
-          id: '1',
-        },
-        indexPattern: undefined,
-        filter: 'dashboard.attributes.otherField:<',
+      const bulkUpdateMultiError = async ([obj1, _obj, obj2], options, mgetResponse) => {
+        callAdminCluster.mockResolvedValueOnce(mgetResponse); // this._callCluster('mget', ...)
+        const bulkResponse = getMockBulkUpdateResponse([obj1, obj2], namespace);
+        callAdminCluster.mockResolvedValue(bulkResponse); // this._writeToCluster('bulk', ...)
+
+        const result = await savedObjectsRepository.bulkUpdate([obj1, _obj, obj2], options);
+        expectClusterCalls('mget', 'bulk');
+        const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)];
+        expectClusterCallArgs({ body }, 2);
+        expect(result).toEqual({
+          saved_objects: [expectSuccess(obj1), expectErrorNotFound(_obj), expectSuccess(obj2)],
+        });
       };
 
-      await expect(savedObjectsRepository.find(findOpts)).rejects.toMatchInlineSnapshot(`
-        [Error: KQLSyntaxError: Expected "(", "{", value, whitespace but "<" found.
-        dashboard.attributes.otherField:<
-        --------------------------------^: Bad Request]
-      `);
-      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(0);
-    });
+      it(`returns error when type is invalid`, async () => {
+        const _obj = { ...obj, type: 'unknownType' };
+        await bulkUpdateError(_obj, undefined, expectErrorNotFound(_obj));
+      });
 
-    it('merges output of getSearchDsl into es request body', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      getSearchDslNS.getSearchDsl.mockReturnValue({ query: 1, aggregations: 2 });
-      await savedObjectsRepository.find({ type: 'foo' });
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        'search',
-        expect.objectContaining({
-          body: expect.objectContaining({
-            query: 1,
-            aggregations: 2,
-          }),
-        })
-      );
-    });
+      it(`returns error when type is hidden`, async () => {
+        const _obj = { ...obj, type: HIDDEN_TYPE };
+        await bulkUpdateError(_obj, undefined, expectErrorNotFound(_obj));
+      });
 
-    it('formats Elasticsearch response when there is no namespace', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      const count = noNamespaceSearchResults.hits.hits.length;
+      it(`returns error when ES is unable to find the document (mget)`, async () => {
+        const _obj = { ...obj, type: MULTI_NAMESPACE_TYPE, found: false };
+        const mgetResponse = getMockMgetResponse([_obj]);
+        await bulkUpdateMultiError([obj1, _obj, obj2], undefined, mgetResponse);
+      });
 
-      const response = await savedObjectsRepository.find({ type: 'foo' });
+      it(`returns error when ES is unable to find the index (mget)`, async () => {
+        const _obj = { ...obj, type: MULTI_NAMESPACE_TYPE };
+        const mgetResponse = { status: 404 };
+        await bulkUpdateMultiError([obj1, _obj, obj2], { namespace }, mgetResponse);
+      });
 
-      expect(response.total).toBe(count);
-      expect(response.saved_objects).toHaveLength(count);
+      it(`returns error when there is a conflict with an existing multi-namespace saved object (mget)`, async () => {
+        const _obj = { ...obj, type: MULTI_NAMESPACE_TYPE };
+        const mgetResponse = getMockMgetResponse([_obj], 'bar-namespace');
+        await bulkUpdateMultiError([obj1, _obj, obj2], { namespace }, mgetResponse);
+      });
 
-      noNamespaceSearchResults.hits.hits.forEach((doc, i) => {
-        expect(response.saved_objects[i]).toEqual({
-          id: doc._id.replace(/(index-pattern|config|globaltype)\:/, ''),
-          type: doc._source.type,
-          ...mockTimestampFields,
-          version: mockVersion,
-          attributes: doc._source[doc._source.type],
-          references: [],
-        });
+      it(`returns error when there is a version conflict (bulk)`, async () => {
+        const esError = { type: 'version_conflict_engine_exception' };
+        await bulkUpdateError(obj, esError, expectErrorConflict(obj));
       });
-    });
 
-    it('formats Elasticsearch response when there is a namespace', async () => {
-      callAdminCluster.mockReturnValue(namespacedSearchResults);
-      const count = namespacedSearchResults.hits.hits.length;
+      it(`returns error when document is missing (bulk)`, async () => {
+        const esError = { type: 'document_missing_exception' };
+        await bulkUpdateError(obj, esError, expectErrorNotFound(obj));
+      });
 
-      const response = await savedObjectsRepository.find({
-        type: 'foo',
-        namespace: 'foo-namespace',
+      it(`returns error reason for other errors (bulk)`, async () => {
+        const esError = { reason: 'some_other_error' };
+        await bulkUpdateError(obj, esError, expectErrorResult(obj, { message: esError.reason }));
       });
 
-      expect(response.total).toBe(count);
-      expect(response.saved_objects).toHaveLength(count);
+      it(`returns error string for other errors if no reason is defined (bulk)`, async () => {
+        const esError = { foo: 'some_other_error' };
+        const expectedError = expectErrorResult(obj, { message: JSON.stringify(esError) });
+        await bulkUpdateError(obj, esError, expectedError);
+      });
+    });
 
-      namespacedSearchResults.hits.hits.forEach((doc, i) => {
-        expect(response.saved_objects[i]).toEqual({
-          id: doc._id.replace(/(foo-namespace\:)?(index-pattern|config|globaltype)\:/, ''),
-          type: doc._source.type,
-          ...mockTimestampFields,
-          version: mockVersion,
-          attributes: doc._source[doc._source.type],
-          references: [],
-        });
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(bulkUpdateSuccess([obj1, obj2])).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveReturnedTimes(1);
       });
     });
 
-    it('accepts per_page/page', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      await savedObjectsRepository.find({ type: 'foo', perPage: 10, page: 6 });
+    describe('returns', () => {
+      const expectSuccessResult = ({ type, id, attributes, references }) => ({
+        type,
+        id,
+        attributes,
+        references,
+        version: mockVersion,
+        ...mockTimestampFields,
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          size: 10,
-          from: 50,
-        })
-      );
-    });
+      it(`formats the ES response`, async () => {
+        const response = await bulkUpdateSuccess([obj1, obj2]);
+        expect(response).toEqual({
+          saved_objects: [obj1, obj2].map(expectSuccessResult),
+        });
+      });
 
-    it('can filter by fields', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      await savedObjectsRepository.find({ type: 'foo', fields: ['title'] });
+      it(`includes references`, async () => {
+        const objects = [obj1, obj2].map(obj => ({ ...obj, references }));
+        const response = await bulkUpdateSuccess(objects);
+        expect(response).toEqual({
+          saved_objects: objects.map(expectSuccessResult),
+        });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          _source: [
-            'foo.title',
-            'namespace',
-            'type',
-            'references',
-            'migrationVersion',
-            'updated_at',
-            'title',
+      it(`handles a mix of successful updates and errors`, async () => {
+        const obj = {
+          type: 'unknownType',
+          id: 'three',
+        };
+        const objects = [obj1, obj, obj2];
+        const mockResponse = getMockBulkUpdateResponse(objects);
+        callAdminCluster.mockResolvedValue(mockResponse); // this._writeToCluster('bulk', ...)
+        const result = await savedObjectsRepository.bulkUpdate(objects);
+        expect(callAdminCluster).toHaveBeenCalledTimes(1);
+        expect(result).toEqual({
+          saved_objects: [expectSuccessResult(obj1), expectError(obj), expectSuccessResult(obj2)],
+        });
+      });
+
+      it(`includes namespaces property for multi-namespace documents`, async () => {
+        const obj = { type: MULTI_NAMESPACE_TYPE, id: 'three' };
+        const result = await bulkUpdateSuccess([obj1, obj]);
+        expect(result).toEqual({
+          saved_objects: [
+            expect.not.objectContaining({ namespaces: expect.anything() }),
+            expect.objectContaining({ namespaces: expect.any(Array) }),
           ],
-        })
-      );
+        });
+      });
     });
+  });
 
-    it('should set rest_total_hits_as_int to true on a request', async () => {
-      callAdminCluster.mockReturnValue(noNamespaceSearchResults);
-      await savedObjectsRepository.find({ type: 'foo' });
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toHaveProperty('rest_total_hits_as_int', true);
+  describe('#create', () => {
+    beforeEach(() => {
+      callAdminCluster.mockImplementation((method, params) => ({
+        _id: params.id,
+        ...mockVersionProps,
+      }));
     });
-  });
 
-  describe('#get', () => {
-    const noNamespaceResult = {
-      _id: 'index-pattern:logstash-*',
-      ...mockVersionProps,
-      _source: {
-        type: 'index-pattern',
-        specialProperty: 'specialValue',
-        ...mockTimestampFields,
-        'index-pattern': {
-          title: 'Testing',
-        },
-      },
-    };
-    const namespacedResult = {
-      _id: 'foo-namespace:index-pattern:logstash-*',
-      ...mockVersionProps,
-      _source: {
-        namespace: 'foo-namespace',
-        type: 'index-pattern',
-        specialProperty: 'specialValue',
-        ...mockTimestampFields,
-        'index-pattern': {
-          title: 'Testing',
-        },
+    const type = 'index-pattern';
+    const attributes = { title: 'Logstash' };
+    const id = 'logstash-*';
+    const namespace = 'foo-namespace';
+    const references = [
+      {
+        name: 'ref_0',
+        type: 'test',
+        id: '123',
       },
-    };
+    ];
 
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
+    const createSuccess = async (type, attributes, options) => {
+      const result = await savedObjectsRepository.create(type, attributes, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(
+        registry.isMultiNamespace(type) && options.overwrite ? 2 : 1
+      );
+      return result;
+    };
 
-      callAdminCluster.mockResolvedValue(noNamespaceResult);
-      await expect(
-        savedObjectsRepository.get('index-pattern', 'logstash-*')
-      ).resolves.toBeDefined();
+    describe('cluster calls', () => {
+      it(`should use the ES create action if ID is undefined and overwrite=true`, async () => {
+        await createSuccess(type, attributes, { overwrite: true });
+        expectClusterCalls('create');
+      });
 
-      expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
-    });
+      it(`should use the ES create action if ID is undefined and overwrite=false`, async () => {
+        await createSuccess(type, attributes);
+        expectClusterCalls('create');
+      });
 
-    it('formats Elasticsearch response when there is no namespace', async () => {
-      callAdminCluster.mockResolvedValue(noNamespaceResult);
-      const response = await savedObjectsRepository.get('index-pattern', 'logstash-*');
-      expect(response).toEqual({
-        id: 'logstash-*',
-        type: 'index-pattern',
-        updated_at: mockTimestamp,
-        version: mockVersion,
-        attributes: {
-          title: 'Testing',
-        },
-        references: [],
+      it(`should use the ES index action if ID is defined and overwrite=true`, async () => {
+        await createSuccess(type, attributes, { id, overwrite: true });
+        expectClusterCalls('index');
       });
-    });
 
-    it('formats Elasticsearch response when there are namespaces', async () => {
-      callAdminCluster.mockResolvedValue(namespacedResult);
-      const response = await savedObjectsRepository.get('index-pattern', 'logstash-*');
-      expect(response).toEqual({
-        id: 'logstash-*',
-        type: 'index-pattern',
-        updated_at: mockTimestamp,
-        version: mockVersion,
-        attributes: {
-          title: 'Testing',
-        },
-        references: [],
+      it(`should use the ES create action if ID is defined and overwrite=false`, async () => {
+        await createSuccess(type, attributes, { id });
+        expectClusterCalls('create');
       });
-    });
 
-    it('prepends namespace and type to the id when providing namespace for namespaced type', async () => {
-      callAdminCluster.mockResolvedValue(namespacedResult);
-      await savedObjectsRepository.get('index-pattern', 'logstash-*', {
-        namespace: 'foo-namespace',
+      it(`should use the ES get action then index action if type is multi-namespace, ID is defined, and overwrite=true`, async () => {
+        await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id, overwrite: true });
+        expectClusterCalls('get', 'index');
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: 'foo-namespace:index-pattern:logstash-*',
-        })
-      );
-    });
+      it(`defaults to empty references array`, async () => {
+        await createSuccess(type, attributes, { id });
+        expectClusterCallArgs({
+          body: expect.objectContaining({ references: [] }),
+        });
+      });
 
-    it(`only prepends type to the id when providing no namespace for namespaced type`, async () => {
-      callAdminCluster.mockResolvedValue(noNamespaceResult);
-      await savedObjectsRepository.get('index-pattern', 'logstash-*');
+      it(`accepts custom references array`, async () => {
+        const test = async references => {
+          await createSuccess(type, attributes, { id, references });
+          expectClusterCallArgs({
+            body: expect.objectContaining({ references }),
+          });
+          callAdminCluster.mockReset();
+        };
+        await test(references);
+        await test(['string']);
+        await test([]);
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: 'index-pattern:logstash-*',
-        })
-      );
-    });
+      it(`doesn't accept custom references if not an array`, async () => {
+        const test = async references => {
+          await createSuccess(type, attributes, { id, references });
+          expectClusterCallArgs({
+            body: expect.not.objectContaining({ references: expect.anything() }),
+          });
+          callAdminCluster.mockReset();
+        };
+        await test('string');
+        await test(123);
+        await test(true);
+        await test(null);
+      });
 
-    it(`doesn't prepend namespace to the id when providing namespace for namespace agnostic type`, async () => {
-      callAdminCluster.mockResolvedValue(namespacedResult);
-      await savedObjectsRepository.get('globaltype', 'logstash-*', {
-        namespace: 'foo-namespace',
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await createSuccess(type, attributes);
+        expectClusterCallArgs({ refresh: 'wait_for' });
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          id: 'globaltype:logstash-*',
-        })
-      );
-    });
-  });
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await createSuccess(type, attributes, { refresh });
+        expectClusterCallArgs({ refresh });
+      });
 
-  describe('#bulkGet', () => {
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
-
-      callAdminCluster.mockReturnValue({ docs: [] });
-      await expect(
-        savedObjectsRepository.bulkGet([
-          { id: 'one', type: 'config' },
-          { id: 'two', type: 'index-pattern' },
-          { id: 'three', type: 'globaltype' },
-        ])
-      ).resolves.toBeDefined();
-
-      expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
-    });
+      it(`should use default index`, async () => {
+        await createSuccess(type, attributes, { id });
+        expectClusterCallArgs({ index: '.kibana-test' });
+      });
 
-    it('prepends type to id when getting objects when there is no namespace', async () => {
-      callAdminCluster.mockReturnValue({ docs: [] });
+      it(`should use custom index`, async () => {
+        await createSuccess(CUSTOM_INDEX_TYPE, attributes, { id });
+        expectClusterCallArgs({ index: 'custom' });
+      });
 
-      await savedObjectsRepository.bulkGet([
-        { id: 'one', type: 'config' },
-        { id: 'two', type: 'index-pattern' },
-        { id: 'three', type: 'globaltype' },
-      ]);
+      it(`self-generates an id if none is provided`, async () => {
+        await createSuccess(type, attributes);
+        expectClusterCallArgs({
+          id: expect.objectContaining(/index-pattern:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}/),
+        });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          body: {
-            docs: [
-              { _id: 'config:one', _index: '.kibana-test' },
-              { _id: 'index-pattern:two', _index: '.kibana-test' },
-              { _id: 'globaltype:three', _index: '.kibana-test' },
-            ],
-          },
-        })
-      );
-    });
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        await createSuccess(type, attributes, { id, namespace });
+        expectClusterCallArgs({ id: `${namespace}:${type}:${id}` });
+      });
 
-    it('prepends namespace and type appropriately to id when getting objects when there is a namespace', async () => {
-      callAdminCluster.mockReturnValue({ docs: [] });
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        await createSuccess(type, attributes, { id });
+        expectClusterCallArgs({ id: `${type}:${id}` });
+      });
 
-      await savedObjectsRepository.bulkGet(
-        [
-          { id: 'one', type: 'config' },
-          { id: 'two', type: 'index-pattern' },
-          { id: 'three', type: 'globaltype' },
-        ],
-        {
-          namespace: 'foo-namespace',
-        }
-      );
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        await createSuccess(NAMESPACE_AGNOSTIC_TYPE, attributes, { id, namespace });
+        expectClusterCallArgs({ id: `${NAMESPACE_AGNOSTIC_TYPE}:${id}` });
+        callAdminCluster.mockReset();
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          body: {
-            docs: [
-              { _id: 'foo-namespace:config:one', _index: '.kibana-test' },
-              { _id: 'foo-namespace:index-pattern:two', _index: '.kibana-test' },
-              { _id: 'globaltype:three', _index: '.kibana-test' },
-            ],
-          },
-        })
-      );
+        await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id, namespace });
+        expectClusterCallArgs({ id: `${MULTI_NAMESPACE_TYPE}:${id}` });
+      });
     });
 
-    it('mockReturnValue early for empty objects argument', async () => {
-      callAdminCluster.mockReturnValue({ docs: [] });
+    describe('errors', () => {
+      it(`throws when type is invalid`, async () => {
+        await expect(savedObjectsRepository.create('unknownType', attributes)).rejects.toThrowError(
+          createUnsupportedTypeError('unknownType')
+        );
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-      const response = await savedObjectsRepository.bulkGet([]);
+      it(`throws when type is hidden`, async () => {
+        await expect(savedObjectsRepository.create(HIDDEN_TYPE, attributes)).rejects.toThrowError(
+          createUnsupportedTypeError(HIDDEN_TYPE)
+        );
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-      expect(response.saved_objects).toHaveLength(0);
-      expect(callAdminCluster).not.toHaveBeenCalled();
+      it(`throws when there is a conflict with an existing multi-namespace saved object (get)`, async () => {
+        const response = getMockGetResponse({
+          type: MULTI_NAMESPACE_TYPE,
+          id,
+          namespace: 'bar-namespace',
+        });
+        callAdminCluster.mockResolvedValue(response); // this._callCluster('get', ...)
+        await expect(
+          savedObjectsRepository.create(MULTI_NAMESPACE_TYPE, attributes, {
+            id,
+            overwrite: true,
+            namespace,
+          })
+        ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_TYPE, id));
+        expectClusterCalls('get');
+      });
+
+      it(`throws when automatic index creation fails`, async () => {
+        // TODO
+      });
+
+      it(`throws when an unexpected failure occurs`, async () => {
+        // TODO
+      });
     });
 
-    it('handles missing ids gracefully', async () => {
-      callAdminCluster.mockResolvedValue({
-        docs: [
-          {
-            _id: 'config:good',
-            found: true,
-            ...mockVersionProps,
-            _source: { ...mockTimestampFields, config: { title: 'Test' } },
-          },
-          {
-            _id: 'config:bad',
-            found: false,
-          },
-        ],
+    describe('migration', () => {
+      beforeEach(() => {
+        migrator.migrateDocument.mockImplementation(mockMigrateDocument);
       });
 
-      const { saved_objects: savedObjects } = await savedObjectsRepository.bulkGet([
-        { id: 'good', type: 'config' },
-        { type: 'config' },
-      ]);
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(createSuccess(type, attributes, { id, namespace })).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
+      });
 
-      expect(savedObjects[1]).toEqual({
-        type: 'config',
-        error: { statusCode: 404, message: 'Not found' },
+      it(`migrates a document and serializes the migrated doc`, async () => {
+        const migrationVersion = mockMigrationVersion;
+        await createSuccess(type, attributes, { id, references, migrationVersion });
+        const doc = { type, id, attributes, references, migrationVersion, ...mockTimestampFields };
+        expectMigrationArgs(doc);
+
+        const migratedDoc = migrator.migrateDocument(doc);
+        expect(serializer.savedObjectToRaw).toHaveBeenLastCalledWith(migratedDoc);
       });
-    });
 
-    it('reports error on missed objects', async () => {
-      callAdminCluster.mockResolvedValue({
-        docs: [
-          {
-            _id: 'config:good',
-            found: true,
-            ...mockVersionProps,
-            _source: { ...mockTimestampFields, config: { title: 'Test' } },
-          },
-          {
-            _id: 'config:bad',
-            found: false,
-          },
-        ],
+      it(`adds namespace to body when providing namespace for single-namespace type`, async () => {
+        await createSuccess(type, attributes, { id, namespace });
+        expectMigrationArgs({ namespace });
       });
 
-      const { saved_objects: savedObjects } = await savedObjectsRepository.bulkGet([
-        { id: 'good', type: 'config' },
-        { id: 'bad', type: 'config' },
-      ]);
+      it(`doesn't add namespace to body when providing no namespace for single-namespace type`, async () => {
+        await createSuccess(type, attributes, { id });
+        expectMigrationArgs({ namespace: expect.anything() }, false);
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`doesn't add namespace to body when not using single-namespace type`, async () => {
+        await createSuccess(NAMESPACE_AGNOSTIC_TYPE, attributes, { id, namespace });
+        expectMigrationArgs({ namespace: expect.anything() }, false, 1);
 
-      expect(savedObjects).toHaveLength(2);
-      expect(savedObjects[0]).toEqual({
-        id: 'good',
-        type: 'config',
-        ...mockTimestampFields,
-        version: mockVersion,
-        attributes: { title: 'Test' },
-        references: [],
+        callAdminCluster.mockReset();
+        await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id });
+        expectMigrationArgs({ namespace: expect.anything() }, false, 2);
       });
-      expect(savedObjects[1]).toEqual({
-        id: 'bad',
-        type: 'config',
-        error: { statusCode: 404, message: 'Not found' },
+
+      it(`adds namespaces to body when providing namespace for multi-namespace type`, async () => {
+        await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id, namespace });
+        expectMigrationArgs({ namespaces: [namespace] });
       });
-    });
 
-    it('returns errors when requesting unsupported types', async () => {
-      callAdminCluster.mockResolvedValue({
-        docs: [
-          {
-            _id: 'one',
-            found: true,
-            ...mockVersionProps,
-            _source: { ...mockTimestampFields, config: { title: 'Test1' } },
-          },
-          {
-            _id: 'three',
-            found: true,
-            ...mockVersionProps,
-            _source: { ...mockTimestampFields, config: { title: 'Test3' } },
-          },
-          {
-            _id: 'five',
-            found: true,
-            ...mockVersionProps,
-            _source: { ...mockTimestampFields, config: { title: 'Test5' } },
-          },
-        ],
+      it(`adds default namespaces to body when providing no namespace for multi-namespace type`, async () => {
+        await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id });
+        expectMigrationArgs({ namespaces: ['default'] });
       });
 
-      const { saved_objects: savedObjects } = await savedObjectsRepository.bulkGet([
-        { id: 'one', type: 'config' },
-        { id: 'two', type: 'invalidtype' },
-        { id: 'three', type: 'config' },
-        { id: 'four', type: 'invalidtype' },
-        { id: 'five', type: 'config' },
-      ]);
+      it(`doesn't add namespaces to body when not using multi-namespace type`, async () => {
+        await createSuccess(type, attributes, { id });
+        expectMigrationArgs({ namespaces: expect.anything() }, false, 1);
 
-      expect(savedObjects).toEqual([
-        {
-          attributes: { title: 'Test1' },
-          id: 'one',
-          ...mockTimestampFields,
-          references: [],
-          type: 'config',
-          version: mockVersion,
-          migrationVersion: undefined,
-        },
-        {
-          attributes: { title: 'Test3' },
-          id: 'three',
-          ...mockTimestampFields,
-          references: [],
-          type: 'config',
-          version: mockVersion,
-          migrationVersion: undefined,
-        },
-        {
-          attributes: { title: 'Test5' },
-          id: 'five',
+        callAdminCluster.mockReset();
+        await createSuccess(NAMESPACE_AGNOSTIC_TYPE, attributes, { id });
+        expectMigrationArgs({ namespaces: expect.anything() }, false, 2);
+      });
+    });
+
+    describe('returns', () => {
+      it(`formats the ES response`, async () => {
+        const result = await createSuccess(type, attributes, { id, namespace, references });
+        expect(result).toEqual({
+          type,
+          id,
           ...mockTimestampFields,
-          references: [],
-          type: 'config',
           version: mockVersion,
-          migrationVersion: undefined,
-        },
-        {
-          error: {
-            error: 'Bad Request',
-            message: "Unsupported saved object type: 'invalidtype': Bad Request",
-            statusCode: 400,
-          },
-          id: 'two',
-          type: 'invalidtype',
-        },
-        {
-          error: {
-            error: 'Bad Request',
-            message: "Unsupported saved object type: 'invalidtype': Bad Request",
-            statusCode: 400,
-          },
-          id: 'four',
-          type: 'invalidtype',
-        },
-      ]);
+          attributes,
+          references,
+        });
+      });
     });
   });
 
-  describe('#update', () => {
-    const id = 'logstash-*';
+  describe('#delete', () => {
     const type = 'index-pattern';
-    const attributes = { title: 'Testing' };
+    const id = 'logstash-*';
+    const namespace = 'foo-namespace';
 
-    beforeEach(() => {
-      callAdminCluster.mockResolvedValue({
-        _id: `${type}:${id}`,
-        ...mockVersionProps,
-        result: 'updated',
+    const deleteSuccess = async (type, id, options) => {
+      if (registry.isMultiNamespace(type)) {
+        const mockGetResponse = getMockGetResponse({ type, id, namespace: options?.namespace });
+        callAdminCluster.mockResolvedValueOnce(mockGetResponse); // this._callCluster('get', ...)
+      }
+      callAdminCluster.mockResolvedValue({ result: 'deleted' }); // this._writeToCluster('delete', ...)
+      const result = await savedObjectsRepository.delete(type, id, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(registry.isMultiNamespace(type) ? 2 : 1);
+      return result;
+    };
+
+    describe('cluster calls', () => {
+      it(`should use the ES delete action when not using a multi-namespace type`, async () => {
+        await deleteSuccess(type, id);
+        expectClusterCalls('delete');
       });
-    });
 
-    it('waits until migrations are complete before proceeding', async () => {
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
+      it(`should use ES get action then delete action when using a multi-namespace type with no namespaces remaining`, async () => {
+        await deleteSuccess(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get', 'delete');
+      });
 
-      await expect(
-        savedObjectsRepository.update('index-pattern', 'logstash-*', attributes, {
-          namespace: 'foo-namespace',
-        })
-      ).resolves.toBeDefined();
+      it(`should use ES get action then update action when using a multi-namespace type with one or more namespaces remaining`, async () => {
+        const mockResponse = getMockGetResponse({ type: MULTI_NAMESPACE_TYPE, id });
+        mockResponse._source.namespaces = ['default', 'some-other-nameespace'];
+        callAdminCluster
+          .mockResolvedValueOnce(mockResponse) // this._callCluster('get', ...)
+          .mockResolvedValue({ result: 'updated' }); // this._writeToCluster('update', ...)
+        await savedObjectsRepository.delete(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get', 'update');
+      });
 
-      expect(migrator.runMigrations).toHaveReturnedTimes(1);
-    });
+      it(`includes the version of the existing document when type is multi-namespace`, async () => {
+        await deleteSuccess(MULTI_NAMESPACE_TYPE, id);
+        const versionProperties = {
+          if_seq_no: mockVersionProps._seq_no,
+          if_primary_term: mockVersionProps._primary_term,
+        };
+        expectClusterCallArgs(versionProperties, 2);
+      });
 
-    it('mockReturnValue current ES document _seq_no and _primary_term encoded as version', async () => {
-      const response = await savedObjectsRepository.update(
-        'index-pattern',
-        'logstash-*',
-        attributes,
-        {
-          namespace: 'foo-namespace',
-          references: [
-            {
-              name: 'ref_0',
-              type: 'test',
-              id: '1',
-            },
-          ],
-        }
-      );
-      expect(response).toEqual({
-        id,
-        type,
-        ...mockTimestampFields,
-        version: mockVersion,
-        attributes,
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
-          },
-        ],
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await deleteSuccess(type, id);
+        expectClusterCallArgs({ refresh: 'wait_for' });
       });
-    });
 
-    it('accepts version', async () => {
-      await savedObjectsRepository.update(
-        type,
-        id,
-        { title: 'Testing' },
-        {
-          version: encodeHitVersion({
-            _seq_no: 100,
-            _primary_term: 200,
-          }),
-        }
-      );
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await deleteSuccess(type, id, { refresh });
+        expectClusterCallArgs({ refresh });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          if_seq_no: 100,
-          if_primary_term: 200,
-        })
-      );
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        await deleteSuccess(type, id, { namespace });
+        expectClusterCallArgs({ id: `${namespace}:${type}:${id}` });
+      });
+
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        await deleteSuccess(type, id);
+        expectClusterCallArgs({ id: `${type}:${id}` });
+      });
+
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        await deleteSuccess(NAMESPACE_AGNOSTIC_TYPE, id, { namespace });
+        expectClusterCallArgs({ id: `${NAMESPACE_AGNOSTIC_TYPE}:${id}` });
+
+        callAdminCluster.mockReset();
+        await deleteSuccess(MULTI_NAMESPACE_TYPE, id, { namespace });
+        expectClusterCallArgs({ id: `${MULTI_NAMESPACE_TYPE}:${id}` });
+      });
     });
 
-    it('does not pass references if omitted', async () => {
-      await savedObjectsRepository.update(type, id, { title: 'Testing' });
+    describe('errors', () => {
+      const expectNotFoundError = async (type, id, options) => {
+        await expect(savedObjectsRepository.delete(type, id, options)).rejects.toThrowError(
+          createGenericNotFoundError(type, id)
+        );
+      };
+
+      it(`throws when type is invalid`, async () => {
+        await expectNotFoundError('unknownType', id);
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
+
+      it(`throws when type is hidden`, async () => {
+        await expectNotFoundError(HIDDEN_TYPE, id);
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
+
+      it(`throws when ES is unable to find the document during get`, async () => {
+        callAdminCluster.mockResolvedValue({ found: false }); // this._callCluster('get', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get');
+      });
+
+      it(`throws when ES is unable to find the index during get`, async () => {
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._callCluster('get', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get');
+      });
+
+      it(`throws when the type is multi-namespace and the document exists, but not in this namespace`, async () => {
+        const response = getMockGetResponse({ type: MULTI_NAMESPACE_TYPE, id, namespace });
+        callAdminCluster.mockResolvedValue(response); // this._callCluster('get', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id, { namespace: 'bar-namespace' });
+        expectClusterCalls('get');
+      });
+
+      it(`throws when ES is unable to find the document during update`, async () => {
+        const mockResponse = getMockGetResponse({ type: MULTI_NAMESPACE_TYPE, id });
+        mockResponse._source.namespaces = ['default', 'some-other-nameespace'];
+        callAdminCluster
+          .mockResolvedValueOnce(mockResponse) // this._callCluster('get', ...)
+          .mockResolvedValue({ status: 404 }); // this._writeToCluster('update', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get', 'update');
+      });
+
+      it(`throws when ES is unable to find the document during delete`, async () => {
+        callAdminCluster.mockResolvedValue({ result: 'not_found' }); // this._writeToCluster('delete', ...)
+        await expectNotFoundError(type, id);
+        expectClusterCalls('delete');
+      });
+
+      it(`throws when ES is unable to find the index during delete`, async () => {
+        callAdminCluster.mockResolvedValue({ error: { type: 'index_not_found_exception' } }); // this._writeToCluster('delete', ...)
+        await expectNotFoundError(type, id);
+        expectClusterCalls('delete');
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).not.toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          body: {
-            doc: expect.objectContaining({
-              references: [],
-            }),
-          },
-        })
-      );
+      it(`throws when ES returns an unexpected response`, async () => {
+        callAdminCluster.mockResolvedValue({ result: 'something unexpected' }); // this._writeToCluster('delete', ...)
+        await expect(savedObjectsRepository.delete(type, id)).rejects.toThrowError(
+          'Unexpected Elasticsearch DELETE response'
+        );
+        expectClusterCalls('delete');
+      });
     });
 
-    it('passes references if they are provided', async () => {
-      await savedObjectsRepository.update(type, id, { title: 'Testing' }, { references: ['foo'] });
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        let callAdminClusterCount = 0;
+        migrator.runMigrations = jest.fn(async () =>
+          // runMigrations should resolve before callAdminCluster is initiated
+          expect(callAdminCluster).toHaveBeenCalledTimes(callAdminClusterCount++)
+        );
+        await expect(deleteSuccess(type, id)).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
+      });
+    });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          body: {
-            doc: expect.objectContaining({
-              references: ['foo'],
-            }),
-          },
-        })
-      );
+    describe('returns', () => {
+      it(`returns an empty object on success`, async () => {
+        const result = await deleteSuccess(type, id);
+        expect(result).toEqual({});
+      });
     });
+  });
 
-    it('passes empty references array if empty references array is provided', async () => {
-      await savedObjectsRepository.update(type, id, { title: 'Testing' }, { references: [] });
+  describe('#deleteByNamespace', () => {
+    const namespace = 'foo-namespace';
+    const mockUpdateResults = {
+      took: 15,
+      timed_out: false,
+      total: 3,
+      updated: 2,
+      deleted: 1,
+      batches: 1,
+      version_conflicts: 0,
+      noops: 0,
+      retries: { bulk: 0, search: 0 },
+      throttled_millis: 0,
+      requests_per_second: -1.0,
+      throttled_until_millis: 0,
+      failures: [],
+    };
 
+    const deleteByNamespaceSuccess = async (namespace, options) => {
+      callAdminCluster.mockResolvedValue(mockUpdateResults);
+      const result = await savedObjectsRepository.deleteByNamespace(namespace, options);
+      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1);
       expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith(
-        expect.any(String),
-        expect.objectContaining({
-          body: {
-            doc: expect.objectContaining({
-              references: [],
-            }),
-          },
-        })
-      );
-    });
+      return result;
+    };
 
-    it(`prepends namespace to the id but doesn't add namespace to body when providing namespace for namespaced type`, async () => {
-      await savedObjectsRepository.update(
-        'index-pattern',
-        'logstash-*',
-        {
-          title: 'Testing',
-        },
-        {
-          namespace: 'foo-namespace',
-          references: [
-            {
-              name: 'ref_0',
-              type: 'test',
-              id: '1',
-            },
-          ],
-        }
-      );
+    describe('cluster calls', () => {
+      it(`should use the ES updateByQuery action`, async () => {
+        await deleteByNamespaceSuccess(namespace);
+        expectClusterCalls('updateByQuery');
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('update', {
-        id: 'foo-namespace:index-pattern:logstash-*',
-        body: {
-          doc: {
-            updated_at: mockTimestamp,
-            'index-pattern': { title: 'Testing' },
-            references: [
-              {
-                name: 'ref_0',
-                type: 'test',
-                id: '1',
-              },
-            ],
-          },
-        },
-        ignore: [404],
-        refresh: 'wait_for',
-        index: '.kibana-test',
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await deleteByNamespaceSuccess(namespace);
+        expectClusterCallArgs({ refresh: 'wait_for' });
       });
-    });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => {
-      await savedObjectsRepository.update(
-        'index-pattern',
-        'logstash-*',
-        {
-          title: 'Testing',
-        },
-        {
-          references: [
-            {
-              name: 'ref_0',
-              type: 'test',
-              id: '1',
-            },
-          ],
-        }
-      );
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await deleteByNamespaceSuccess(namespace, { refresh });
+        expectClusterCallArgs({ refresh });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('update', {
-        id: 'index-pattern:logstash-*',
-        body: {
-          doc: {
-            updated_at: mockTimestamp,
-            'index-pattern': { title: 'Testing' },
-            references: [
-              {
-                name: 'ref_0',
-                type: 'test',
-                id: '1',
-              },
-            ],
-          },
-        },
-        ignore: [404],
-        refresh: 'wait_for',
-        index: '.kibana-test',
+      it(`should use all indices for types that are not namespace-agnostic`, async () => {
+        await deleteByNamespaceSuccess(namespace);
+        expectClusterCallArgs({ index: ['.kibana-test', 'custom'] }, 1);
       });
     });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => {
-      await savedObjectsRepository.update(
-        'globaltype',
-        'foo',
-        {
-          name: 'bar',
-        },
-        {
-          namespace: 'foo-namespace',
-          references: [
-            {
-              name: 'ref_0',
-              type: 'test',
-              id: '1',
-            },
-          ],
-        }
-      );
-
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster).toHaveBeenCalledWith('update', {
-        id: 'globaltype:foo',
-        body: {
-          doc: {
-            updated_at: mockTimestamp,
-            globaltype: { name: 'bar' },
-            references: [
-              {
-                name: 'ref_0',
-                type: 'test',
-                id: '1',
-              },
-            ],
-          },
-        },
-        ignore: [404],
-        refresh: 'wait_for',
-        index: '.kibana-test',
+    describe('errors', () => {
+      it(`throws when namespace is not a string`, async () => {
+        const test = async namespace => {
+          await expect(savedObjectsRepository.deleteByNamespace(namespace)).rejects.toThrowError(
+            `namespace is required, and must be a string`
+          );
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
+        await test(undefined);
+        await test(['namespace']);
+        await test(123);
+        await test(true);
       });
     });
 
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      await savedObjectsRepository.update('globaltype', 'foo', {
-        name: 'bar',
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(deleteByNamespaceSuccess(namespace)).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
       });
+    });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: 'wait_for',
+    describe('returns', () => {
+      it(`returns the query results on success`, async () => {
+        const result = await deleteByNamespaceSuccess(namespace);
+        expect(result).toEqual(mockUpdateResults);
       });
     });
 
-    it('accepts a custom refresh setting', async () => {
-      await savedObjectsRepository.update(
-        'globaltype',
-        'foo',
-        {
-          name: 'bar',
-        },
-        {
-          refresh: true,
-          namespace: 'foo-namespace',
-        }
-      );
-
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: true,
+    describe('search dsl', () => {
+      it(`constructs a query using all multi-namespace types, and another using all single-namespace types`, async () => {
+        await deleteByNamespaceSuccess(namespace);
+        const allTypes = registry.getAllTypes().map(type => type.name);
+        expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, {
+          namespace,
+          type: allTypes.filter(type => !registry.isNamespaceAgnostic(type)),
+        });
       });
     });
   });
 
-  describe('#bulkUpdate', () => {
-    const { generateSavedObject, reset } = (() => {
-      let count = 0;
+  describe('#find', () => {
+    const generateSearchResults = namespace => {
       return {
-        generateSavedObject(overrides) {
-          count++;
-          return _.merge(
+        hits: {
+          total: 4,
+          hits: [
             {
-              type: 'index-pattern',
-              id: `logstash-${count}`,
-              attributes: { title: `Testing ${count}` },
-              references: [
-                {
-                  name: 'ref_0',
-                  type: 'test',
-                  id: '1',
+              _index: '.kibana',
+              _id: `${namespace ? `${namespace}:` : ''}index-pattern:logstash-*`,
+              _score: 1,
+              ...mockVersionProps,
+              _source: {
+                namespace,
+                type: 'index-pattern',
+                ...mockTimestampFields,
+                'index-pattern': {
+                  title: 'logstash-*',
+                  timeFieldName: '@timestamp',
+                  notExpandable: true,
                 },
-              ],
+              },
             },
-            overrides
-          );
-        },
-        reset() {
-          count = 0;
+            {
+              _index: '.kibana',
+              _id: `${namespace ? `${namespace}:` : ''}config:6.0.0-alpha1`,
+              _score: 1,
+              ...mockVersionProps,
+              _source: {
+                namespace,
+                type: 'config',
+                ...mockTimestampFields,
+                config: {
+                  buildNum: 8467,
+                  defaultIndex: 'logstash-*',
+                },
+              },
+            },
+            {
+              _index: '.kibana',
+              _id: `${namespace ? `${namespace}:` : ''}index-pattern:stocks-*`,
+              _score: 1,
+              ...mockVersionProps,
+              _source: {
+                namespace,
+                type: 'index-pattern',
+                ...mockTimestampFields,
+                'index-pattern': {
+                  title: 'stocks-*',
+                  timeFieldName: '@timestamp',
+                  notExpandable: true,
+                },
+              },
+            },
+            {
+              _index: '.kibana',
+              _id: `${NAMESPACE_AGNOSTIC_TYPE}:something`,
+              _score: 1,
+              ...mockVersionProps,
+              _source: {
+                type: NAMESPACE_AGNOSTIC_TYPE,
+                ...mockTimestampFields,
+                [NAMESPACE_AGNOSTIC_TYPE]: {
+                  name: 'bar',
+                },
+              },
+            },
+          ],
         },
       };
-    })();
+    };
 
-    beforeEach(() => {
-      reset();
-    });
+    const type = 'index-pattern';
+    const namespace = 'foo-namespace';
 
-    const mockValidResponse = objects =>
-      callAdminCluster.mockReturnValue({
-        items: objects.map(items => ({
-          update: {
-            _id: `${items.type}:${items.id}`,
-            ...mockVersionProps,
-            result: 'updated',
-          },
-        })),
+    const findSuccess = async (options, namespace) => {
+      callAdminCluster.mockResolvedValue(generateSearchResults(namespace));
+      const result = await savedObjectsRepository.find(options);
+      expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1);
+      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      return result;
+    };
+
+    describe('cluster calls', () => {
+      it(`should use the ES search action`, async () => {
+        await findSuccess({ type });
+        expectClusterCalls('search');
+      });
+
+      it(`merges output of getSearchDsl into es request body`, async () => {
+        const query = { query: 1, aggregations: 2 };
+        getSearchDslNS.getSearchDsl.mockReturnValue(query);
+        await findSuccess({ type });
+        expectClusterCallArgs({ body: expect.objectContaining({ ...query }) });
       });
 
-    it('waits until migrations are complete before proceeding', async () => {
-      const objects = [generateSavedObject(), generateSavedObject()];
+      it(`accepts per_page/page`, async () => {
+        await findSuccess({ type, perPage: 10, page: 6 });
+        expectClusterCallArgs({
+          size: 10,
+          from: 50,
+        });
+      });
 
-      migrator.runMigrations = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled());
+      it(`can filter by fields`, async () => {
+        await findSuccess({ type, fields: ['title'] });
+        expectClusterCallArgs({
+          _source: [
+            `${type}.title`,
+            'namespace',
+            'namespaces',
+            'type',
+            'references',
+            'migrationVersion',
+            'updated_at',
+            'title',
+          ],
+        });
+      });
 
-      mockValidResponse(objects);
+      it(`should set rest_total_hits_as_int to true on a request`, async () => {
+        await findSuccess({ type });
+        expectClusterCallArgs({ rest_total_hits_as_int: true });
+      });
 
-      await expect(
-        savedObjectsRepository.bulkUpdate([generateSavedObject()])
-      ).resolves.toBeDefined();
+      it(`should not make a cluster call when attempting to find only invalid or hidden types`, async () => {
+        const test = async types => {
+          await savedObjectsRepository.find({ type: types });
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
 
-      expect(migrator.runMigrations).toHaveReturnedTimes(1);
+        await test('unknownType');
+        await test(HIDDEN_TYPE);
+        await test(['unknownType', HIDDEN_TYPE]);
+      });
     });
 
-    it('returns current ES document, _seq_no and _primary_term encoded as version', async () => {
-      const objects = [generateSavedObject(), generateSavedObject()];
-
-      mockValidResponse(objects);
+    describe('errors', () => {
+      it(`throws when type is not defined`, async () => {
+        await expect(savedObjectsRepository.find({})).rejects.toThrowError(
+          'options.type must be a string or an array of strings'
+        );
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-      const response = await savedObjectsRepository.bulkUpdate(objects);
+      it(`throws when searchFields is defined but not an array`, async () => {
+        await expect(
+          savedObjectsRepository.find({ type, searchFields: 'string' })
+        ).rejects.toThrowError('options.searchFields must be an array');
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-      expect(response.saved_objects[0]).toMatchObject({
-        ..._.pick(objects[0], 'id', 'type', 'attributes'),
-        version: mockVersion,
-        references: objects[0].references,
+      it(`throws when fields is defined but not an array`, async () => {
+        await expect(savedObjectsRepository.find({ type, fields: 'string' })).rejects.toThrowError(
+          'options.fields must be an array'
+        );
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
-      expect(response.saved_objects[1]).toMatchObject({
-        ..._.pick(objects[1], 'id', 'type', 'attributes'),
-        version: mockVersion,
-        references: objects[1].references,
+
+      it(`throws when KQL filter syntax is invalid`, async () => {
+        const findOpts = {
+          namespace,
+          search: 'foo*',
+          searchFields: ['foo'],
+          type: ['dashboard'],
+          sortField: 'name',
+          sortOrder: 'desc',
+          defaultSearchOperator: 'AND',
+          hasReference: {
+            type: 'foo',
+            id: '1',
+          },
+          indexPattern: undefined,
+          filter: 'dashboard.attributes.otherField:<',
+        };
+
+        await expect(savedObjectsRepository.find(findOpts)).rejects.toMatchInlineSnapshot(`
+                          [Error: KQLSyntaxError: Expected "(", "{", value, whitespace but "<" found.
+                          dashboard.attributes.otherField:<
+                          --------------------------------^: Bad Request]
+                      `);
+        expect(getSearchDslNS.getSearchDsl).not.toHaveBeenCalled();
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
     });
 
-    it('handles a mix of succesfull updates and errors', async () => {
-      const objects = [
-        generateSavedObject(),
-        {
-          type: 'invalid-type',
-          id: 'invalid',
-          attributes: { title: 'invalid' },
-        },
-        generateSavedObject(),
-        generateSavedObject({
-          id: 'version_clash',
-        }),
-      ];
-
-      callAdminCluster.mockReturnValue({
-        items: objects
-          // remove invalid from mocks
-          .filter(item => item.id !== 'invalid')
-          .map(items => {
-            switch (items.id) {
-              case 'version_clash':
-                return {
-                  update: {
-                    _id: `${items.type}:${items.id}`,
-                    error: {
-                      type: 'version_conflict_engine_exception',
-                    },
-                  },
-                };
-              default:
-                return {
-                  update: {
-                    _id: `${items.type}:${items.id}`,
-                    ...mockVersionProps,
-                    result: 'updated',
-                  },
-                };
-            }
-          }),
-      });
-
-      const {
-        saved_objects: [firstUpdatedObject, invalidType, secondUpdatedObject, versionClashObject],
-      } = await savedObjectsRepository.bulkUpdate(objects);
-
-      expect(firstUpdatedObject).toMatchObject({
-        ..._.pick(objects[0], 'id', 'type', 'attributes', 'references'),
-        version: mockVersion,
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(findSuccess({ type })).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
       });
+    });
 
-      expect(invalidType).toMatchObject({
-        ..._.pick(objects[1], 'id', 'type'),
-        error: SavedObjectsErrorHelpers.createGenericNotFoundError('invalid-type', 'invalid').output
-          .payload,
-      });
+    describe('returns', () => {
+      it(`formats the ES response when there is no namespace`, async () => {
+        const noNamespaceSearchResults = generateSearchResults();
+        callAdminCluster.mockReturnValue(noNamespaceSearchResults);
+        const count = noNamespaceSearchResults.hits.hits.length;
 
-      expect(secondUpdatedObject).toMatchObject({
-        ..._.pick(objects[2], 'id', 'type', 'attributes', 'references'),
-        version: mockVersion,
-      });
+        const response = await savedObjectsRepository.find({ type });
+
+        expect(response.total).toBe(count);
+        expect(response.saved_objects).toHaveLength(count);
 
-      expect(versionClashObject).toMatchObject({
-        ..._.pick(objects[3], 'id', 'type'),
-        error: { statusCode: 409, message: 'version conflict, document already exists' },
+        noNamespaceSearchResults.hits.hits.forEach((doc, i) => {
+          expect(response.saved_objects[i]).toEqual({
+            id: doc._id.replace(/(index-pattern|config|globalType)\:/, ''),
+            type: doc._source.type,
+            ...mockTimestampFields,
+            version: mockVersion,
+            attributes: doc._source[doc._source.type],
+            references: [],
+          });
+        });
       });
-    });
 
-    it('doesnt call Elasticsearch if there are no valid objects to update', async () => {
-      const objects = [
-        {
-          type: 'invalid-type',
-          id: 'invalid',
-          attributes: { title: 'invalid' },
-        },
-        {
-          type: 'invalid-type',
-          id: 'invalid 2',
-          attributes: { title: 'invalid' },
-        },
-      ];
+      it(`formats the ES response when there is a namespace`, async () => {
+        const namespacedSearchResults = generateSearchResults(namespace);
+        callAdminCluster.mockReturnValue(namespacedSearchResults);
+        const count = namespacedSearchResults.hits.hits.length;
 
-      const {
-        saved_objects: [invalidType, invalidType2],
-      } = await savedObjectsRepository.bulkUpdate(objects);
+        const response = await savedObjectsRepository.find({ type, namespace });
 
-      expect(callAdminCluster).not.toHaveBeenCalled();
+        expect(response.total).toBe(count);
+        expect(response.saved_objects).toHaveLength(count);
 
-      expect(invalidType).toMatchObject({
-        ..._.pick(objects[0], 'id', 'type'),
-        error: SavedObjectsErrorHelpers.createGenericNotFoundError('invalid-type', 'invalid').output
-          .payload,
+        namespacedSearchResults.hits.hits.forEach((doc, i) => {
+          expect(response.saved_objects[i]).toEqual({
+            id: doc._id.replace(/(foo-namespace\:)?(index-pattern|config|globalType)\:/, ''),
+            type: doc._source.type,
+            ...mockTimestampFields,
+            version: mockVersion,
+            attributes: doc._source[doc._source.type],
+            references: [],
+          });
+        });
       });
 
-      expect(invalidType2).toMatchObject({
-        ..._.pick(objects[1], 'id', 'type'),
-        error: SavedObjectsErrorHelpers.createGenericNotFoundError('invalid-type', 'invalid 2')
-          .output.payload,
+      it(`should return empty results when attempting to find only invalid or hidden types`, async () => {
+        const test = async types => {
+          const result = await savedObjectsRepository.find({ type: types });
+          expect(result).toEqual(expect.objectContaining({ saved_objects: [] }));
+        };
+
+        await test('unknownType');
+        await test(HIDDEN_TYPE);
+        await test(['unknownType', HIDDEN_TYPE]);
       });
     });
 
-    it('accepts version', async () => {
-      const objects = [
-        generateSavedObject({
-          version: encodeHitVersion({
-            _seq_no: 100,
-            _primary_term: 200,
-          }),
-        }),
-        generateSavedObject({
-          version: encodeHitVersion({
-            _seq_no: 300,
-            _primary_term: 400,
-          }),
-        }),
-      ];
+    describe('search dsl', () => {
+      it(`passes mappings, registry, search, defaultSearchOperator, searchFields, type, sortField, sortOrder and hasReference to getSearchDsl`, async () => {
+        const relevantOpts = {
+          namespace,
+          search: 'foo*',
+          searchFields: ['foo'],
+          type: [type],
+          sortField: 'name',
+          sortOrder: 'desc',
+          defaultSearchOperator: 'AND',
+          hasReference: {
+            type: 'foo',
+            id: '1',
+          },
+          kueryNode: undefined,
+        };
 
-      mockValidResponse(objects);
+        await findSuccess(relevantOpts, namespace);
+        expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, relevantOpts);
+      });
+
+      it(`accepts KQL filter and passes kueryNode to getSearchDsl`, async () => {
+        const findOpts = {
+          namespace,
+          search: 'foo*',
+          searchFields: ['foo'],
+          type: ['dashboard'],
+          sortField: 'name',
+          sortOrder: 'desc',
+          defaultSearchOperator: 'AND',
+          hasReference: {
+            type: 'foo',
+            id: '1',
+          },
+          indexPattern: undefined,
+          filter: 'dashboard.attributes.otherField: *',
+        };
+
+        await findSuccess(findOpts, namespace);
+        const { kueryNode } = getSearchDslNS.getSearchDsl.mock.calls[0][2];
+        expect(kueryNode).toMatchInlineSnapshot(`
+          Object {
+            "arguments": Array [
+              Object {
+                "type": "literal",
+                "value": "dashboard.otherField",
+              },
+              Object {
+                "type": "wildcard",
+                "value": "@kuery-wildcard@",
+              },
+              Object {
+                "type": "literal",
+                "value": false,
+              },
+            ],
+            "function": "is",
+            "type": "function",
+          }
+        `);
+      });
 
-      await savedObjectsRepository.bulkUpdate(objects);
+      it(`supports multiple types`, async () => {
+        const types = ['config', 'index-pattern'];
+        await findSuccess({ type: types });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+        expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(
+          mappings,
+          registry,
+          expect.objectContaining({
+            type: types,
+          })
+        );
+      });
 
-      const [
-        ,
-        {
-          body: [{ update: firstUpdate }, , { update: secondUpdate }],
-        },
-      ] = callAdminCluster.mock.calls[0];
+      it(`filters out invalid types`, async () => {
+        const types = ['config', 'unknownType', 'index-pattern'];
+        await findSuccess({ type: types });
 
-      expect(firstUpdate).toMatchObject({
-        if_seq_no: 100,
-        if_primary_term: 200,
+        expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(
+          mappings,
+          registry,
+          expect.objectContaining({
+            type: ['config', 'index-pattern'],
+          })
+        );
       });
 
-      expect(secondUpdate).toMatchObject({
-        if_seq_no: 300,
-        if_primary_term: 400,
+      it(`filters out hidden types`, async () => {
+        const types = ['config', HIDDEN_TYPE, 'index-pattern'];
+        await findSuccess({ type: types });
+
+        expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(
+          mappings,
+          registry,
+          expect.objectContaining({
+            type: ['config', 'index-pattern'],
+          })
+        );
       });
     });
+  });
 
-    it('does not pass references if omitted', async () => {
-      const objects = [
-        {
-          type: 'index-pattern',
-          id: `logstash-no-ref`,
-          attributes: { title: `Testing no-ref` },
-        },
-      ];
+  describe('#get', () => {
+    const type = 'index-pattern';
+    const id = 'logstash-*';
+    const namespace = 'foo-namespace';
+
+    const getSuccess = async (type, id, options) => {
+      const response = getMockGetResponse({ type, id, namespace: options?.namespace });
+      callAdminCluster.mockResolvedValue(response);
+      const result = await savedObjectsRepository.get(type, id, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      return result;
+    };
 
-      mockValidResponse(objects);
+    describe('cluster calls', () => {
+      it(`should use the ES get action`, async () => {
+        await getSuccess(type, id);
+        expectClusterCalls('get');
+      });
 
-      await savedObjectsRepository.bulkUpdate(objects);
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        await getSuccess(type, id, { namespace });
+        expectClusterCallArgs({ id: `${namespace}:${type}:${id}` });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        await getSuccess(type, id);
+        expectClusterCallArgs({ id: `${type}:${id}` });
+      });
 
-      const [
-        ,
-        {
-          body: [, { doc: firstDoc }],
-        },
-      ] = callAdminCluster.mock.calls[0];
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        await getSuccess(NAMESPACE_AGNOSTIC_TYPE, id, { namespace });
+        expectClusterCallArgs({ id: `${NAMESPACE_AGNOSTIC_TYPE}:${id}` });
 
-      expect(firstDoc).not.toMatchObject({
-        references: [],
+        callAdminCluster.mockReset();
+        await getSuccess(MULTI_NAMESPACE_TYPE, id, { namespace });
+        expectClusterCallArgs({ id: `${MULTI_NAMESPACE_TYPE}:${id}` });
       });
     });
 
-    it('passes references if they are provided', async () => {
-      const objects = [
-        generateSavedObject({
-          references: [
-            {
-              name: 'ref_0',
-              type: 'test',
-              id: '1',
-            },
-          ],
-        }),
-      ];
+    describe('errors', () => {
+      const expectNotFoundError = async (type, id, options) => {
+        await expect(savedObjectsRepository.get(type, id, options)).rejects.toThrowError(
+          createGenericNotFoundError(type, id)
+        );
+      };
 
-      mockValidResponse(objects);
+      it(`throws when type is invalid`, async () => {
+        await expectNotFoundError('unknownType', id);
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-      await savedObjectsRepository.bulkUpdate(objects);
+      it(`throws when type is hidden`, async () => {
+        await expectNotFoundError(HIDDEN_TYPE, id);
+        expect(callAdminCluster).not.toHaveBeenCalled();
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`throws when ES is unable to find the document during get`, async () => {
+        callAdminCluster.mockResolvedValue({ found: false });
+        await expectNotFoundError(type, id);
+        expectClusterCalls('get');
+      });
 
-      const [
-        ,
-        {
-          body: [, { doc }],
-        },
-      ] = callAdminCluster.mock.calls[0];
+      it(`throws when ES is unable to find the index during get`, async () => {
+        callAdminCluster.mockResolvedValue({ status: 404 });
+        await expectNotFoundError(type, id);
+        expectClusterCalls('get');
+      });
 
-      expect(doc).toMatchObject({
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
-          },
-        ],
+      it(`throws when type is multi-namespace and the document exists, but not in this namespace`, async () => {
+        const response = getMockGetResponse({ type: MULTI_NAMESPACE_TYPE, id, namespace });
+        callAdminCluster.mockResolvedValue(response);
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id, { namespace: 'bar-namespace' });
+        expectClusterCalls('get');
       });
     });
 
-    it('passes empty references array if empty references array is provided', async () => {
-      const objects = [
-        {
-          type: 'index-pattern',
-          id: `logstash-no-ref`,
-          attributes: { title: `Testing no-ref` },
-          references: [],
-        },
-      ];
-
-      mockValidResponse(objects);
-
-      await savedObjectsRepository.bulkUpdate(objects);
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(getSuccess(type, id)).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
+      });
+    });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+    describe('returns', () => {
+      it(`formats the ES response`, async () => {
+        const result = await getSuccess(type, id);
+        expect(result).toEqual({
+          id,
+          type,
+          updated_at: mockTimestamp,
+          version: mockVersion,
+          attributes: {
+            title: 'Testing',
+          },
+          references: [],
+        });
+      });
 
-      const [
-        ,
-        {
-          body: [, { doc }],
-        },
-      ] = callAdminCluster.mock.calls[0];
+      it(`includes namespaces if type is multi-namespace`, async () => {
+        const result = await getSuccess(MULTI_NAMESPACE_TYPE, id);
+        expect(result).toMatchObject({
+          namespaces: expect.any(Array),
+        });
+      });
 
-      expect(doc).toMatchObject({
-        references: [],
+      it(`doesn't include namespaces if type is not multi-namespace`, async () => {
+        const result = await getSuccess(type, id);
+        expect(result).not.toMatchObject({
+          namespaces: expect.anything(),
+        });
       });
     });
+  });
 
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      const objects = [
-        {
-          type: 'index-pattern',
-          id: `logstash-no-ref`,
-          attributes: { title: `Testing no-ref` },
-          references: [],
+  describe('#incrementCounter', () => {
+    const type = 'config';
+    const id = 'one';
+    const field = 'buildNum';
+    const namespace = 'foo-namespace';
+
+    const incrementCounterSuccess = async (type, id, field, options) => {
+      const isMultiNamespace = registry.isMultiNamespace(type);
+      if (isMultiNamespace) {
+        const response = getMockGetResponse({ type, id, namespace: options?.namespace });
+        callAdminCluster.mockResolvedValueOnce(response); // this._callCluster('get', ...)
+      }
+      callAdminCluster.mockImplementation((method, params) => ({
+        _id: params.id,
+        ...mockVersionProps,
+        _index: '.kibana',
+        get: {
+          found: true,
+          _source: {
+            type,
+            ...mockTimestampFields,
+            [type]: {
+              [field]: 8468,
+              defaultIndex: 'logstash-*',
+            },
+          },
         },
-      ];
-
-      mockValidResponse(objects);
+      }));
+      const result = await savedObjectsRepository.incrementCounter(type, id, field, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(isMultiNamespace ? 2 : 1);
+      return result;
+    };
 
-      await savedObjectsRepository.bulkUpdate(objects);
+    describe('cluster calls', () => {
+      it(`should use the ES update action if type is not multi-namespace`, async () => {
+        await incrementCounterSuccess(type, id, field, { namespace });
+        expectClusterCalls('update');
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`should use the ES get action then update action if type is multi-namespace, ID is defined, and overwrite=true`, async () => {
+        await incrementCounterSuccess(MULTI_NAMESPACE_TYPE, id, field, { namespace });
+        expectClusterCalls('get', 'update');
+      });
 
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({ refresh: 'wait_for' });
-    });
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await incrementCounterSuccess(type, id, field, { namespace });
+        expectClusterCallArgs({ refresh: 'wait_for' });
+      });
 
-    it('accepts a custom refresh setting', async () => {
-      const objects = [
-        {
-          type: 'index-pattern',
-          id: `logstash-no-ref`,
-          attributes: { title: `Testing no-ref` },
-          references: [],
-        },
-      ];
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await incrementCounterSuccess(type, id, field, { namespace, refresh });
+        expectClusterCallArgs({ refresh });
+      });
 
-      mockValidResponse(objects);
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        await incrementCounterSuccess(type, id, field, { namespace });
+        expectClusterCallArgs({ id: `${namespace}:${type}:${id}` });
+      });
 
-      await savedObjectsRepository.bulkUpdate(objects, { refresh: true });
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        await incrementCounterSuccess(type, id, field);
+        expectClusterCallArgs({ id: `${type}:${id}` });
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        await incrementCounterSuccess(NAMESPACE_AGNOSTIC_TYPE, id, field, { namespace });
+        expectClusterCallArgs({ id: `${NAMESPACE_AGNOSTIC_TYPE}:${id}` });
 
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({ refresh: true });
+        callAdminCluster.mockReset();
+        await incrementCounterSuccess(MULTI_NAMESPACE_TYPE, id, field, { namespace });
+        expectClusterCallArgs({ id: `${MULTI_NAMESPACE_TYPE}:${id}` });
+      });
     });
 
-    it(`prepends namespace to the id but doesn't add namespace to body when providing namespace for namespaced type`, async () => {
-      const objects = [generateSavedObject(), generateSavedObject()];
+    describe('errors', () => {
+      const expectUnsupportedTypeError = async (type, id, field) => {
+        await expect(savedObjectsRepository.incrementCounter(type, id, field)).rejects.toThrowError(
+          createUnsupportedTypeError(type)
+        );
+      };
 
-      mockValidResponse(objects);
+      it(`throws when type is not a string`, async () => {
+        const test = async type => {
+          await expect(
+            savedObjectsRepository.incrementCounter(type, id, field)
+          ).rejects.toThrowError(`"type" argument must be a string`);
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
 
-      await savedObjectsRepository.bulkUpdate(objects, {
-        namespace: 'foo-namespace',
+        await test(null);
+        await test(42);
+        await test(false);
+        await test({});
       });
 
-      const [
-        ,
-        {
-          body: [
-            { update: firstUpdate },
-            { doc: firstUpdateDoc },
-            { update: secondUpdate },
-            { doc: secondUpdateDoc },
-          ],
-        },
-      ] = callAdminCluster.mock.calls[0];
+      it(`throws when counterFieldName is not a string`, async () => {
+        const test = async field => {
+          await expect(
+            savedObjectsRepository.incrementCounter(type, id, field)
+          ).rejects.toThrowError(`"counterFieldName" argument must be a string`);
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
 
-      expect(firstUpdate).toMatchObject({
-        _id: 'foo-namespace:index-pattern:logstash-1',
-        _index: '.kibana-test',
+        await test(null);
+        await test(42);
+        await test(false);
+        await test({});
       });
 
-      expect(firstUpdateDoc).toMatchObject({
-        updated_at: mockTimestamp,
-        'index-pattern': { title: 'Testing 1' },
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
-          },
-        ],
+      it(`throws when type is invalid`, async () => {
+        await expectUnsupportedTypeError('unknownType', id, field);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
 
-      expect(secondUpdate).toMatchObject({
-        _id: 'foo-namespace:index-pattern:logstash-2',
-        _index: '.kibana-test',
+      it(`throws when type is hidden`, async () => {
+        await expectUnsupportedTypeError(HIDDEN_TYPE, id, field);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
 
-      expect(secondUpdateDoc).toMatchObject({
-        updated_at: mockTimestamp,
-        'index-pattern': { title: 'Testing 2' },
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
-          },
-        ],
+      it(`throws when there is a conflict with an existing multi-namespace saved object (get)`, async () => {
+        const response = getMockGetResponse({
+          type: MULTI_NAMESPACE_TYPE,
+          id,
+          namespace: 'bar-namespace',
+        });
+        callAdminCluster.mockResolvedValue(response); // this._callCluster('get', ...)
+        await expect(
+          savedObjectsRepository.incrementCounter(MULTI_NAMESPACE_TYPE, id, field, { namespace })
+        ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_TYPE, id));
+        expectClusterCalls('get');
       });
     });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => {
-      const objects = [generateSavedObject(), generateSavedObject()];
-
-      mockValidResponse(objects);
+    describe('migration', () => {
+      beforeEach(() => {
+        migrator.migrateDocument.mockImplementation(mockMigrateDocument);
+      });
 
-      await savedObjectsRepository.bulkUpdate(objects);
+      it(`waits until migrations are complete before proceeding`, async () => {
+        migrator.runMigrations = jest.fn(async () =>
+          expect(callAdminCluster).not.toHaveBeenCalled()
+        );
+        await expect(
+          incrementCounterSuccess(type, id, field, { namespace })
+        ).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveBeenCalledTimes(1);
+      });
 
-      const [
-        ,
-        {
-          body: [
-            { update: firstUpdate },
-            { doc: firstUpdateDoc },
-            { update: secondUpdate },
-            { doc: secondUpdateDoc },
-          ],
-        },
-      ] = callAdminCluster.mock.calls[0];
+      it(`migrates a document and serializes the migrated doc`, async () => {
+        const migrationVersion = mockMigrationVersion;
+        await incrementCounterSuccess(type, id, field, { migrationVersion });
+        const attributes = { buildNum: 1 }; // this is added by the incrementCounter function
+        const doc = { type, id, attributes, migrationVersion, ...mockTimestampFields };
+        expectMigrationArgs(doc);
 
-      expect(firstUpdate).toMatchObject({
-        _id: 'index-pattern:logstash-1',
-        _index: '.kibana-test',
+        const migratedDoc = migrator.migrateDocument(doc);
+        expect(serializer.savedObjectToRaw).toHaveBeenLastCalledWith(migratedDoc);
       });
+    });
 
-      expect(firstUpdateDoc).toMatchObject({
-        updated_at: mockTimestamp,
-        'index-pattern': { title: 'Testing 1' },
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
+    describe('returns', () => {
+      it(`formats the ES response`, async () => {
+        callAdminCluster.mockImplementation((method, params) => ({
+          _id: params.id,
+          ...mockVersionProps,
+          _index: '.kibana',
+          get: {
+            found: true,
+            _source: {
+              type: 'config',
+              ...mockTimestampFields,
+              config: {
+                buildNum: 8468,
+                defaultIndex: 'logstash-*',
+              },
+            },
           },
-        ],
-      });
-
-      expect(secondUpdate).toMatchObject({
-        _id: 'index-pattern:logstash-2',
-        _index: '.kibana-test',
-      });
+        }));
 
-      expect(secondUpdateDoc).toMatchObject({
-        updated_at: mockTimestamp,
-        'index-pattern': { title: 'Testing 2' },
-        references: [
+        const response = await savedObjectsRepository.incrementCounter(
+          'config',
+          '6.0.0-alpha1',
+          'buildNum',
           {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
+            namespace: 'foo-namespace',
+          }
+        );
+
+        expect(response).toEqual({
+          type: 'config',
+          id: '6.0.0-alpha1',
+          ...mockTimestampFields,
+          version: mockVersion,
+          attributes: {
+            buildNum: 8468,
+            defaultIndex: 'logstash-*',
           },
-        ],
+        });
       });
     });
+  });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => {
-      const objects = [
-        generateSavedObject({
-          type: 'globaltype',
-          id: 'foo',
-          namespace: 'foo-namespace',
-        }),
-      ];
+  describe('#deleteFromNamespaces', () => {
+    const id = 'some-id';
+    const type = MULTI_NAMESPACE_TYPE;
+    const namespace1 = 'default';
+    const namespace2 = 'foo-namespace';
+    const namespace3 = 'bar-namespace';
+
+    const mockGetResponse = (type, id, namespaces) => {
+      // mock a document that exists in two namespaces
+      const mockResponse = getMockGetResponse({ type, id });
+      mockResponse._source.namespaces = namespaces;
+      callAdminCluster.mockResolvedValueOnce(mockResponse); // this._callCluster('get', ...)
+    };
+
+    const deleteFromNamespacesSuccess = async (
+      type,
+      id,
+      namespaces,
+      currentNamespaces,
+      options
+    ) => {
+      mockGetResponse(type, id, currentNamespaces); // this._callCluster('get', ...)
+      const isDelete = currentNamespaces.every(namespace => namespaces.includes(namespace));
+      callAdminCluster.mockResolvedValue({
+        _id: `${type}:${id}`,
+        ...mockVersionProps,
+        result: isDelete ? 'deleted' : 'updated',
+      }); // this._writeToCluster('delete', ...) *or* this._writeToCluster('update', ...)
+      const result = await savedObjectsRepository.deleteFromNamespaces(
+        type,
+        id,
+        namespaces,
+        options
+      );
+      expect(callAdminCluster).toHaveBeenCalledTimes(2);
+      return result;
+    };
 
-      mockValidResponse(objects);
+    describe('cluster calls', () => {
+      describe('delete action', () => {
+        const deleteFromNamespacesSuccessDelete = async (expectFn, options, _type = type) => {
+          const test = async namespaces => {
+            await deleteFromNamespacesSuccess(_type, id, namespaces, namespaces, options);
+            expectFn();
+            callAdminCluster.mockReset();
+          };
+          await test([namespace1]);
+          await test([namespace1, namespace2]);
+        };
+
+        it(`should use ES get action then delete action if the object has no namespaces remaining`, async () => {
+          const expectFn = () => expectClusterCalls('get', 'delete');
+          await deleteFromNamespacesSuccessDelete(expectFn);
+        });
 
-      await savedObjectsRepository.bulkUpdate(objects);
+        it(`formats the ES requests`, async () => {
+          const expectFn = () => {
+            expectClusterCallArgs({ id: `${type}:${id}` }, 1);
+            const versionProperties = {
+              if_seq_no: mockVersionProps._seq_no,
+              if_primary_term: mockVersionProps._primary_term,
+            };
+            expectClusterCallArgs({ id: `${type}:${id}`, ...versionProperties }, 2);
+          };
+          await deleteFromNamespacesSuccessDelete(expectFn);
+        });
 
-      const [
-        ,
-        {
-          body: [{ update }, { doc }],
-        },
-      ] = callAdminCluster.mock.calls[0];
+        it(`defaults to a refresh setting of wait_for`, async () => {
+          await deleteFromNamespacesSuccessDelete(() =>
+            expectClusterCallArgs({ refresh: 'wait_for' }, 2)
+          );
+        });
 
-      expect(update).toMatchObject({
-        _id: 'globaltype:foo',
-        _index: '.kibana-test',
-      });
+        it(`accepts a custom refresh setting`, async () => {
+          const refresh = 'foo';
+          const expectFn = () => expectClusterCallArgs({ refresh }, 2);
+          await deleteFromNamespacesSuccessDelete(expectFn, { refresh });
+        });
 
-      expect(doc).toMatchObject({
-        updated_at: mockTimestamp,
-        globaltype: { title: 'Testing 1' },
-        references: [
-          {
-            name: 'ref_0',
-            type: 'test',
-            id: '1',
-          },
-        ],
+        it(`should use default index`, async () => {
+          const expectFn = () => expectClusterCallArgs({ index: '.kibana-test' }, 2);
+          await deleteFromNamespacesSuccessDelete(expectFn);
+        });
+
+        it(`should use custom index`, async () => {
+          const expectFn = () => expectClusterCallArgs({ index: 'custom' }, 2);
+          await deleteFromNamespacesSuccessDelete(expectFn, {}, MULTI_NAMESPACE_CUSTOM_INDEX_TYPE);
+        });
       });
-    });
-  });
 
-  describe('#incrementCounter', () => {
-    beforeEach(() => {
-      callAdminCluster.mockImplementation((method, params) => ({
-        _id: params.id,
-        ...mockVersionProps,
-        _index: '.kibana',
-        get: {
-          found: true,
-          _source: {
-            type: 'config',
-            ...mockTimestampFields,
-            config: {
-              buildNum: 8468,
-              defaultIndex: 'logstash-*',
-            },
-          },
-        },
-      }));
-    });
+      describe('update action', () => {
+        const deleteFromNamespacesSuccessUpdate = async (expectFn, options, _type = type) => {
+          const test = async remaining => {
+            const currentNamespaces = [namespace1].concat(remaining);
+            await deleteFromNamespacesSuccess(_type, id, [namespace1], currentNamespaces, options);
+            expectFn();
+            callAdminCluster.mockReset();
+          };
+          await test([namespace2]);
+          await test([namespace2, namespace3]);
+        };
+
+        it(`should use ES get action then update action if the object has one or more namespaces remaining`, async () => {
+          await deleteFromNamespacesSuccessUpdate(() => expectClusterCalls('get', 'update'));
+        });
 
-    it('formats Elasticsearch response', async () => {
-      callAdminCluster.mockImplementation((method, params) => ({
-        _id: params.id,
-        ...mockVersionProps,
-        _index: '.kibana',
-        get: {
-          found: true,
-          _source: {
-            type: 'config',
-            ...mockTimestampFields,
-            config: {
-              buildNum: 8468,
-              defaultIndex: 'logstash-*',
-            },
-          },
-        },
-      }));
+        it(`formats the ES requests`, async () => {
+          let ctr = 0;
+          const expectFn = () => {
+            expectClusterCallArgs({ id: `${type}:${id}` }, 1);
+            const namespaces = ctr++ === 0 ? [namespace2] : [namespace2, namespace3];
+            const versionProperties = {
+              if_seq_no: mockVersionProps._seq_no,
+              if_primary_term: mockVersionProps._primary_term,
+            };
+            expectClusterCallArgs(
+              {
+                id: `${type}:${id}`,
+                ...versionProperties,
+                body: { doc: { ...mockTimestampFields, namespaces } },
+              },
+              2
+            );
+          };
+          await deleteFromNamespacesSuccessUpdate(expectFn);
+        });
 
-      const response = await savedObjectsRepository.incrementCounter(
-        'config',
-        '6.0.0-alpha1',
-        'buildNum',
-        {
-          namespace: 'foo-namespace',
-        }
-      );
+        it(`defaults to a refresh setting of wait_for`, async () => {
+          const expectFn = () => expectClusterCallArgs({ refresh: 'wait_for' }, 2);
+          await deleteFromNamespacesSuccessUpdate(expectFn);
+        });
 
-      expect(response).toEqual({
-        type: 'config',
-        id: '6.0.0-alpha1',
-        ...mockTimestampFields,
-        version: mockVersion,
-        attributes: {
-          buildNum: 8468,
-          defaultIndex: 'logstash-*',
-        },
+        it(`accepts a custom refresh setting`, async () => {
+          const refresh = 'foo';
+          const expectFn = () => expectClusterCallArgs({ refresh }, 2);
+          await deleteFromNamespacesSuccessUpdate(expectFn, { refresh });
+        });
+
+        it(`should use default index`, async () => {
+          const expectFn = () => expectClusterCallArgs({ index: '.kibana-test' }, 2);
+          await deleteFromNamespacesSuccessUpdate(expectFn);
+        });
+
+        it(`should use custom index`, async () => {
+          const expectFn = () => expectClusterCallArgs({ index: 'custom' }, 2);
+          await deleteFromNamespacesSuccessUpdate(expectFn, {}, MULTI_NAMESPACE_CUSTOM_INDEX_TYPE);
+        });
       });
     });
 
-    it('migrates the doc if an upsert is required', async () => {
-      migrator.migrateDocument = doc => {
-        doc.attributes.buildNum = 42;
-        doc.migrationVersion = { foo: '2.3.4' };
-        doc.references = [{ name: 'search_0', type: 'search', id: '123' }];
-        return doc;
+    describe('errors', () => {
+      const expectNotFoundError = async (type, id, namespaces, options) => {
+        await expect(
+          savedObjectsRepository.deleteFromNamespaces(type, id, namespaces, options)
+        ).rejects.toThrowError(createGenericNotFoundError(type, id));
+      };
+      const expectBadRequestError = async (type, id, namespaces, message) => {
+        await expect(
+          savedObjectsRepository.deleteFromNamespaces(type, id, namespaces)
+        ).rejects.toThrowError(createBadRequestError(message));
       };
 
-      await savedObjectsRepository.incrementCounter('config', 'doesnotexist', 'buildNum', {
-        namespace: 'foo-namespace',
+      it(`throws when type is invalid`, async () => {
+        await expectNotFoundError('unknownType', id, [namespace1, namespace2]);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        body: {
-          upsert: {
-            config: { buildNum: 42 },
-            migrationVersion: { foo: '2.3.4' },
-            type: 'config',
-            ...mockTimestampFields,
-            references: [{ name: 'search_0', type: 'search', id: '123' }],
-          },
-        },
+      it(`throws when type is hidden`, async () => {
+        await expectNotFoundError(HIDDEN_TYPE, id, [namespace1, namespace2]);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
-    });
 
-    it('defaults to a refresh setting of `wait_for`', async () => {
-      await savedObjectsRepository.incrementCounter('config', 'doesnotexist', 'buildNum', {
-        namespace: 'foo-namespace',
+      it(`throws when type is not namespace-agnostic`, async () => {
+        const test = async type => {
+          const message = `${type} doesn't support multiple namespaces`;
+          await expectBadRequestError(type, id, [namespace1, namespace2], message);
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
+        await test('index-pattern');
+        await test(NAMESPACE_AGNOSTIC_TYPE);
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: 'wait_for',
+      it(`throws when namespaces is an empty array`, async () => {
+        const test = async namespaces => {
+          const message = 'namespaces must be a non-empty array of strings';
+          await expectBadRequestError(type, id, namespaces, message);
+          expect(callAdminCluster).not.toHaveBeenCalled();
+        };
+        await test([]);
       });
-    });
 
-    it('accepts a custom refresh setting', async () => {
-      await savedObjectsRepository.incrementCounter('config', 'doesnotexist', 'buildNum', {
-        namespace: 'foo-namespace',
-        refresh: true,
+      it(`throws when ES is unable to find the document during get`, async () => {
+        callAdminCluster.mockResolvedValue({ found: false }); // this._callCluster('get', ...)
+        await expectNotFoundError(type, id, [namespace1, namespace2]);
+        expectClusterCalls('get');
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
-      expect(callAdminCluster.mock.calls[0][1]).toMatchObject({
-        refresh: true,
+      it(`throws when ES is unable to find the index during get`, async () => {
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._callCluster('get', ...)
+        await expectNotFoundError(type, id, [namespace1, namespace2]);
+        expectClusterCalls('get');
       });
-    });
 
-    it(`prepends namespace to the id but doesn't add namespace to body when providing namespace for namespaced type`, async () => {
-      await savedObjectsRepository.incrementCounter('config', '6.0.0-alpha1', 'buildNum', {
-        namespace: 'foo-namespace',
+      it(`throws when the document exists, but not in this namespace`, async () => {
+        mockGetResponse(type, id, [namespace1]); // this._callCluster('get', ...)
+        await expectNotFoundError(type, id, [namespace1], { namespace: 'some-other-namespace' });
+        expectClusterCalls('get');
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`throws when ES is unable to find the document during delete`, async () => {
+        mockGetResponse(type, id, [namespace1]); // this._callCluster('get', ...)
+        callAdminCluster.mockResolvedValue({ result: 'not_found' }); // this._writeToCluster('delete', ...)
+        await expectNotFoundError(type, id, [namespace1]);
+        expectClusterCalls('get', 'delete');
+      });
+
+      it(`throws when ES is unable to find the index during delete`, async () => {
+        mockGetResponse(type, id, [namespace1]); // this._callCluster('get', ...)
+        callAdminCluster.mockResolvedValue({ error: { type: 'index_not_found_exception' } }); // this._writeToCluster('delete', ...)
+        await expectNotFoundError(type, id, [namespace1]);
+        expectClusterCalls('get', 'delete');
+      });
+
+      it(`throws when ES returns an unexpected response`, async () => {
+        mockGetResponse(type, id, [namespace1]); // this._callCluster('get', ...)
+        callAdminCluster.mockResolvedValue({ result: 'something unexpected' }); // this._writeToCluster('delete', ...)
+        await expect(
+          savedObjectsRepository.deleteFromNamespaces(type, id, [namespace1])
+        ).rejects.toThrowError('Unexpected Elasticsearch DELETE response');
+        expectClusterCalls('get', 'delete');
+      });
+
+      it(`throws when ES is unable to find the document during update`, async () => {
+        mockGetResponse(type, id, [namespace1, namespace2]); // this._callCluster('get', ...)
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._writeToCluster('update', ...)
+        await expectNotFoundError(type, id, [namespace1]);
+        expectClusterCalls('get', 'update');
+      });
+    });
 
-      const requestDoc = callAdminCluster.mock.calls[0][1];
-      expect(requestDoc.id).toBe('foo-namespace:config:6.0.0-alpha1');
-      expect(requestDoc.body.script.params.type).toBe('config');
-      expect(requestDoc.body.upsert.type).toBe('config');
-      expect(requestDoc).toHaveProperty('body.upsert.config');
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        let callAdminClusterCount = 0;
+        migrator.runMigrations = jest.fn(async () =>
+          // runMigrations should resolve before callAdminCluster is initiated
+          expect(callAdminCluster).toHaveBeenCalledTimes(callAdminClusterCount++)
+        );
+        await expect(
+          deleteFromNamespacesSuccess(type, id, [namespace1], [namespace1])
+        ).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveReturnedTimes(2);
+      });
     });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => {
-      await savedObjectsRepository.incrementCounter('config', '6.0.0-alpha1', 'buildNum');
+    describe('returns', () => {
+      it(`returns an empty object on success (delete)`, async () => {
+        const test = async namespaces => {
+          const result = await deleteFromNamespacesSuccess(type, id, namespaces, namespaces);
+          expect(result).toEqual({});
+          callAdminCluster.mockReset();
+        };
+        await test([namespace1]);
+        await test([namespace1, namespace2]);
+      });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`returns an empty object on success (update)`, async () => {
+        const test = async remaining => {
+          const currentNamespaces = [namespace1].concat(remaining);
+          const result = await deleteFromNamespacesSuccess(
+            type,
+            id,
+            [namespace1],
+            currentNamespaces
+          );
+          expect(result).toEqual({});
+          callAdminCluster.mockReset();
+        };
+        await test([namespace2]);
+        await test([namespace2, namespace3]);
+      });
 
-      const requestDoc = callAdminCluster.mock.calls[0][1];
-      expect(requestDoc.id).toBe('config:6.0.0-alpha1');
-      expect(requestDoc.body.script.params.type).toBe('config');
-      expect(requestDoc.body.upsert.type).toBe('config');
-      expect(requestDoc).toHaveProperty('body.upsert.config');
+      it(`succeeds when the document doesn't exist in all of the targeted namespaces`, async () => {
+        const namespaces = [namespace2];
+        const currentNamespaces = [namespace1];
+        const result = await deleteFromNamespacesSuccess(type, id, namespaces, currentNamespaces);
+        expect(result).toEqual({});
+      });
     });
+  });
 
-    it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => {
-      callAdminCluster.mockImplementation((method, params) => ({
-        _id: params.id,
+  describe('#update', () => {
+    const id = 'logstash-*';
+    const type = 'index-pattern';
+    const attributes = { title: 'Testing' };
+    const namespace = 'foo-namespace';
+    const references = [
+      {
+        name: 'ref_0',
+        type: 'test',
+        id: '1',
+      },
+    ];
+
+    const updateSuccess = async (type, id, attributes, options) => {
+      if (registry.isMultiNamespace(type)) {
+        const mockGetResponse = getMockGetResponse({ type, id, namespace: options?.namespace });
+        callAdminCluster.mockResolvedValueOnce(mockGetResponse); // this._callCluster('get', ...)
+      }
+      callAdminCluster.mockResolvedValue({
+        _id: `${type}:${id}`,
         ...mockVersionProps,
-        _index: '.kibana',
-        get: {
-          found: true,
-          _source: {
-            type: 'globaltype',
-            ...mockTimestampFields,
-            globaltype: {
-              counter: 1,
-            },
-          },
-        },
-      }));
+        result: 'updated',
+        ...(registry.isMultiNamespace(type) && {
+          // don't need the rest of the source for test purposes, just the namespaces attribute
+          get: { _source: { namespaces: [options?.namespace ?? 'default'] } },
+        }),
+      }); // this._writeToCluster('update', ...)
+      const result = await savedObjectsRepository.update(type, id, attributes, options);
+      expect(callAdminCluster).toHaveBeenCalledTimes(registry.isMultiNamespace(type) ? 2 : 1);
+      return result;
+    };
 
-      await savedObjectsRepository.incrementCounter('globaltype', 'foo', 'counter', {
-        namespace: 'foo-namespace',
+    describe('cluster calls', () => {
+      it(`should use the ES get action then update action when type is multi-namespace`, async () => {
+        await updateSuccess(MULTI_NAMESPACE_TYPE, id, attributes);
+        expectClusterCalls('get', 'update');
       });
 
-      expect(callAdminCluster).toHaveBeenCalledTimes(1);
+      it(`should use the ES update action when type is not multi-namespace`, async () => {
+        await updateSuccess(type, id, attributes);
+        expectClusterCalls('update');
+      });
 
-      const requestDoc = callAdminCluster.mock.calls[0][1];
-      expect(requestDoc.id).toBe('globaltype:foo');
-      expect(requestDoc.body.script.params.type).toBe('globaltype');
-      expect(requestDoc.body.upsert.type).toBe('globaltype');
-      expect(requestDoc).toHaveProperty('body.upsert.globaltype');
-    });
+      it(`defaults to no references array`, async () => {
+        await updateSuccess(type, id, attributes);
+        expectClusterCallArgs({
+          body: { doc: expect.not.objectContaining({ references: expect.anything() }) },
+        });
+      });
 
-    it('should assert that the "type" and "counterFieldName" arguments are strings', () => {
-      expect.assertions(6);
-
-      expect(
-        savedObjectsRepository.incrementCounter(null, '6.0.0-alpha1', 'buildNum', {
-          namespace: 'foo-namespace',
-        })
-      ).rejects.toEqual(new Error('"type" argument must be a string'));
-
-      expect(
-        savedObjectsRepository.incrementCounter(42, '6.0.0-alpha1', 'buildNum', {
-          namespace: 'foo-namespace',
-        })
-      ).rejects.toEqual(new Error('"type" argument must be a string'));
-
-      expect(
-        savedObjectsRepository.incrementCounter({}, '6.0.0-alpha1', 'buildNum', {
-          namespace: 'foo-namespace',
-        })
-      ).rejects.toEqual(new Error('"type" argument must be a string'));
-
-      expect(
-        savedObjectsRepository.incrementCounter('config', '6.0.0-alpha1', null, {
-          namespace: 'foo-namespace',
-        })
-      ).rejects.toEqual(new Error('"counterFieldName" argument must be a string'));
-
-      expect(
-        savedObjectsRepository.incrementCounter('config', '6.0.0-alpha1', 42, {
-          namespace: 'foo-namespace',
-        })
-      ).rejects.toEqual(new Error('"counterFieldName" argument must be a string'));
-
-      expect(
-        savedObjectsRepository.incrementCounter(
-          'config',
-          '6.0.0-alpha1',
-          {},
-          {
-            namespace: 'foo-namespace',
-          }
-        )
-      ).rejects.toEqual(new Error('"counterFieldName" argument must be a string'));
-    });
-  });
+      it(`accepts custom references array`, async () => {
+        const test = async references => {
+          await updateSuccess(type, id, attributes, { references });
+          expectClusterCallArgs({
+            body: { doc: expect.objectContaining({ references }) },
+          });
+          callAdminCluster.mockReset();
+        };
+        await test(references);
+        await test(['string']);
+        await test([]);
+      });
+
+      it(`doesn't accept custom references if not an array`, async () => {
+        const test = async references => {
+          await updateSuccess(type, id, attributes, { references });
+          expectClusterCallArgs({
+            body: { doc: expect.not.objectContaining({ references: expect.anything() }) },
+          });
+          callAdminCluster.mockReset();
+        };
+        await test('string');
+        await test(123);
+        await test(true);
+        await test(null);
+      });
+
+      it(`defaults to a refresh setting of wait_for`, async () => {
+        await updateSuccess(type, id, { foo: 'bar' });
+        expectClusterCallArgs({ refresh: 'wait_for' });
+      });
+
+      it(`accepts a custom refresh setting`, async () => {
+        const refresh = 'foo';
+        await updateSuccess(type, id, { foo: 'bar' }, { refresh });
+        expectClusterCallArgs({ refresh });
+      });
+
+      it(`defaults to the version of the existing document when type is multi-namespace`, async () => {
+        await updateSuccess(MULTI_NAMESPACE_TYPE, id, attributes, { references });
+        const versionProperties = {
+          if_seq_no: mockVersionProps._seq_no,
+          if_primary_term: mockVersionProps._primary_term,
+        };
+        expectClusterCallArgs(versionProperties, 2);
+      });
+
+      it(`accepts version`, async () => {
+        await updateSuccess(type, id, attributes, {
+          version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }),
+        });
+        expectClusterCallArgs({ if_seq_no: 100, if_primary_term: 200 });
+      });
 
-  describe('types on custom index', () => {
-    it("should error when attempting to 'update' an unsupported type", async () => {
-      await expect(
-        savedObjectsRepository.update('hiddenType', 'bogus', { title: 'some title' })
-      ).rejects.toEqual(new Error('Saved object [hiddenType/bogus] not found'));
-    });
-  });
+      it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => {
+        await updateSuccess(type, id, attributes, { namespace });
+        expectClusterCallArgs({ id: expect.stringMatching(`${namespace}:${type}:${id}`) });
+      });
 
-  describe('unsupported types', () => {
-    it("should error when attempting to 'update' an unsupported type", async () => {
-      await expect(
-        savedObjectsRepository.update('hiddenType', 'bogus', { title: 'some title' })
-      ).rejects.toEqual(new Error('Saved object [hiddenType/bogus] not found'));
-    });
+      it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => {
+        await updateSuccess(type, id, attributes, { references });
+        expectClusterCallArgs({ id: expect.stringMatching(`${type}:${id}`) });
+      });
 
-    it("should error when attempting to 'get' an unsupported type", async () => {
-      await expect(savedObjectsRepository.get('hiddenType')).rejects.toEqual(
-        new Error('Not Found')
-      );
-    });
+      it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => {
+        await updateSuccess(NAMESPACE_AGNOSTIC_TYPE, id, attributes, { namespace });
+        expectClusterCallArgs({ id: expect.stringMatching(`${NAMESPACE_AGNOSTIC_TYPE}:${id}`) });
 
-    it("should return an error object when attempting to 'create' an unsupported type", async () => {
-      await expect(
-        savedObjectsRepository.create('hiddenType', { title: 'some title' })
-      ).rejects.toEqual(new Error("Unsupported saved object type: 'hiddenType': Bad Request"));
-    });
+        callAdminCluster.mockReset();
+        await updateSuccess(MULTI_NAMESPACE_TYPE, id, attributes, { namespace });
+        expectClusterCallArgs({ id: expect.stringMatching(`${MULTI_NAMESPACE_TYPE}:${id}`) }, 2);
+      });
 
-    it("should not return hidden saved ojects when attempting to 'find' support and unsupported types", async () => {
-      callAdminCluster.mockReturnValue({
-        hits: {
-          total: 1,
-          hits: [
-            {
-              _id: 'one',
-              _source: {
-                updated_at: mockTimestamp,
-                type: 'config',
-              },
-              references: [],
-            },
-          ],
-        },
+      it(`includes _sourceIncludes when type is multi-namespace`, async () => {
+        await updateSuccess(MULTI_NAMESPACE_TYPE, id, attributes);
+        expectClusterCallArgs({ _sourceIncludes: ['namespaces'] }, 2);
       });
-      const results = await savedObjectsRepository.find({ type: ['hiddenType', 'config'] });
-      expect(results).toEqual({
-        total: 1,
-        saved_objects: [
-          {
-            id: 'one',
-            references: [],
-            type: 'config',
-            updated_at: mockTimestamp,
-          },
-        ],
-        page: 1,
-        per_page: 20,
+
+      it(`doesn't include _sourceIncludes when type is not multi-namespace`, async () => {
+        await updateSuccess(type, id, attributes);
+        expect(callAdminCluster).toHaveBeenLastCalledWith(
+          expect.any(String),
+          expect.not.objectContaining({
+            _sourceIncludes: expect.anything(),
+          })
+        );
       });
     });
 
-    it("should return empty results when attempting to 'find' an unsupported type", async () => {
-      callAdminCluster.mockReturnValue({
-        hits: {
-          total: 0,
-          hits: [],
-        },
+    describe('errors', () => {
+      const expectNotFoundError = async (type, id) => {
+        await expect(savedObjectsRepository.update(type, id)).rejects.toThrowError(
+          createGenericNotFoundError(type, id)
+        );
+      };
+
+      it(`throws when type is invalid`, async () => {
+        await expectNotFoundError('unknownType', id);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
-      const results = await savedObjectsRepository.find({ type: 'hiddenType' });
-      expect(results).toEqual({
-        total: 0,
-        saved_objects: [],
-        page: 1,
-        per_page: 20,
+
+      it(`throws when type is hidden`, async () => {
+        await expectNotFoundError(HIDDEN_TYPE, id);
+        expect(callAdminCluster).not.toHaveBeenCalled();
       });
-    });
 
-    it("should return empty results when attempting to 'find' more than one unsupported types", async () => {
-      const findParams = { type: ['hiddenType', 'hiddenType2'] };
-      callAdminCluster.mockReturnValue({
-        status: 200,
-        hits: {
-          total: 0,
-          hits: [],
-        },
+      it(`throws when ES is unable to find the document during get`, async () => {
+        callAdminCluster.mockResolvedValue({ found: false }); // this._callCluster('get', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get');
       });
-      const results = await savedObjectsRepository.find(findParams);
-      expect(results).toEqual({
-        total: 0,
-        saved_objects: [],
-        page: 1,
-        per_page: 20,
+
+      it(`throws when ES is unable to find the index during get`, async () => {
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._callCluster('get', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id);
+        expectClusterCalls('get');
       });
-    });
 
-    it("should error when attempting to 'delete' hidden types", async () => {
-      await expect(savedObjectsRepository.delete('hiddenType')).rejects.toEqual(
-        new Error('Not Found')
-      );
+      it(`throws when type is multi-namespace and the document exists, but not in this namespace`, async () => {
+        const response = getMockGetResponse({ type: MULTI_NAMESPACE_TYPE, id, namespace });
+        callAdminCluster.mockResolvedValue(response); // this._callCluster('get', ...)
+        await expectNotFoundError(MULTI_NAMESPACE_TYPE, id, { namespace: 'bar-namespace' });
+        expectClusterCalls('get');
+      });
+
+      it(`throws when ES is unable to find the document during update`, async () => {
+        callAdminCluster.mockResolvedValue({ status: 404 }); // this._writeToCluster('update', ...)
+        await expectNotFoundError(type, id);
+        expectClusterCalls('update');
+      });
     });
 
-    it("should error when attempting to 'bulkCreate' an unsupported type", async () => {
-      callAdminCluster.mockReturnValue({
-        items: [
-          {
-            index: {
-              _id: 'one',
-              _seq_no: 1,
-              _primary_term: 1,
-              _type: 'config',
-              attributes: {
-                title: 'Test One',
-              },
-            },
-          },
-        ],
-      });
-      const results = await savedObjectsRepository.bulkCreate([
-        { type: 'config', id: 'one', attributes: { title: 'Test One' } },
-        { type: 'hiddenType', id: 'two', attributes: { title: 'Test Two' } },
-      ]);
-      expect(results).toEqual({
-        saved_objects: [
-          {
-            type: 'config',
-            id: 'one',
-            attributes: { title: 'Test One' },
-            references: [],
-            version: 'WzEsMV0=',
-            updated_at: mockTimestamp,
-          },
-          {
-            error: {
-              error: 'Bad Request',
-              message: "Unsupported saved object type: 'hiddenType': Bad Request",
-              statusCode: 400,
-            },
-            id: 'two',
-            type: 'hiddenType',
-          },
-        ],
+    describe('migration', () => {
+      it(`waits until migrations are complete before proceeding`, async () => {
+        let callAdminClusterCount = 0;
+        migrator.runMigrations = jest.fn(async () =>
+          // runMigrations should resolve before callAdminCluster is initiated
+          expect(callAdminCluster).toHaveBeenCalledTimes(callAdminClusterCount++)
+        );
+        await expect(updateSuccess(type, id, attributes)).resolves.toBeDefined();
+        expect(migrator.runMigrations).toHaveReturnedTimes(1);
       });
     });
 
-    it("should error when attempting to 'incrementCounter' for an unsupported type", async () => {
-      await expect(
-        savedObjectsRepository.incrementCounter('hiddenType', 'doesntmatter', 'fieldArg')
-      ).rejects.toEqual(new Error("Unsupported saved object type: 'hiddenType': Bad Request"));
+    describe('returns', () => {
+      it(`returns _seq_no and _primary_term encoded as version`, async () => {
+        const result = await updateSuccess(type, id, attributes, {
+          namespace,
+          references,
+        });
+        expect(result).toEqual({
+          id,
+          type,
+          ...mockTimestampFields,
+          version: mockVersion,
+          attributes,
+          references,
+        });
+      });
+
+      it(`includes namespaces if type is multi-namespace`, async () => {
+        const result = await updateSuccess(MULTI_NAMESPACE_TYPE, id, attributes);
+        expect(result).toMatchObject({
+          namespaces: expect.any(Array),
+        });
+      });
+
+      it(`doesn't include namespaces if type is not multi-namespace`, async () => {
+        const result = await updateSuccess(type, id, attributes);
+        expect(result).not.toMatchObject({
+          namespaces: expect.anything(),
+        });
+      });
     });
   });
 });
diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts
index 72a7867854b60..5f17c11792763 100644
--- a/src/core/server/saved_objects/service/lib/repository.ts
+++ b/src/core/server/saved_objects/service/lib/repository.ts
@@ -45,6 +45,8 @@ import {
   SavedObjectsBulkUpdateObject,
   SavedObjectsBulkUpdateOptions,
   SavedObjectsDeleteOptions,
+  SavedObjectsAddToNamespacesOptions,
+  SavedObjectsDeleteFromNamespacesOptions,
 } from '../saved_objects_client';
 import {
   SavedObject,
@@ -60,20 +62,12 @@ import { validateConvertFilterToKueryNode } from './filter_utils';
 // so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient.
 
 // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
-type Left<T> = {
-  tag: 'Left';
-  error: T;
-};
+type Left = { tag: 'Left'; error: Record<string, any> };
 // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
-type Right<T> = {
-  tag: 'Right';
-  value: T;
-};
-
-type Either<L, R> = Left<L> | Right<R>;
-const isLeft = <L, R>(either: Either<L, R>): either is Left<L> => {
-  return either.tag === 'Left';
-};
+type Right = { tag: 'Right'; value: Record<string, any> };
+type Either = Left | Right;
+const isLeft = (either: Either): either is Left => either.tag === 'Left';
+const isRight = (either: Either): either is Right => either.tag === 'Right';
 
 export interface SavedObjectsRepositoryOptions {
   index: string;
@@ -220,8 +214,8 @@ export class SavedObjectsRepository {
     const {
       id,
       migrationVersion,
-      overwrite = false,
       namespace,
+      overwrite = false,
       references = [],
       refresh = DEFAULT_REFRESH_SETTING,
     } = options;
@@ -230,22 +224,36 @@ export class SavedObjectsRepository {
       throw SavedObjectsErrorHelpers.createUnsupportedTypeError(type);
     }
 
-    const method = id && !overwrite ? 'create' : 'index';
     const time = this._getCurrentTime();
+    let savedObjectNamespace;
+    let savedObjectNamespaces: string[] | undefined;
+
+    if (this._registry.isSingleNamespace(type) && namespace) {
+      savedObjectNamespace = namespace;
+    } else if (this._registry.isMultiNamespace(type)) {
+      if (id && overwrite) {
+        // we will overwrite a multi-namespace saved object if it exists; if that happens, ensure we preserve its included namespaces
+        savedObjectNamespaces = await this.preflightGetNamespaces(type, id, namespace);
+      } else {
+        savedObjectNamespaces = getSavedObjectNamespaces(namespace);
+      }
+    }
 
     try {
       const migrated = this._migrator.migrateDocument({
         id,
         type,
-        namespace,
+        ...(savedObjectNamespace && { namespace: savedObjectNamespace }),
+        ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }),
         attributes,
         migrationVersion,
         updated_at: time,
-        references,
+        ...(Array.isArray(references) && { references }),
       });
 
       const raw = this._serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc);
 
+      const method = id && overwrite ? 'index' : 'create';
       const response = await this._writeToCluster(method, {
         id: raw._id,
         index: this.getIndexForType(type),
@@ -282,10 +290,9 @@ export class SavedObjectsRepository {
   ): Promise<SavedObjectsBulkResponse<T>> {
     const { namespace, overwrite = false, refresh = DEFAULT_REFRESH_SETTING } = options;
     const time = this._getCurrentTime();
-    const bulkCreateParams: object[] = [];
 
-    let requestIndexCounter = 0;
-    const expectedResults: Array<Either<any, any>> = objects.map(object => {
+    let bulkGetRequestIndexCounter = 0;
+    const expectedResults: Either[] = objects.map(object => {
       if (!this._allowedTypes.includes(object.type)) {
         return {
           tag: 'Left' as 'Left',
@@ -297,9 +304,73 @@ export class SavedObjectsRepository {
         };
       }
 
-      const method = object.id && !overwrite ? 'create' : 'index';
+      const method = object.id && overwrite ? 'index' : 'create';
+      const requiresNamespacesCheck =
+        method === 'index' && this._registry.isMultiNamespace(object.type);
+
+      return {
+        tag: 'Right' as 'Right',
+        value: {
+          method,
+          object,
+          ...(requiresNamespacesCheck && { esRequestIndex: bulkGetRequestIndexCounter++ }),
+        },
+      };
+    });
+
+    const bulkGetDocs = expectedResults
+      .filter(isRight)
+      .filter(({ value }) => value.esRequestIndex !== undefined)
+      .map(({ value: { object: { type, id } } }) => ({
+        _id: this._serializer.generateRawId(namespace, type, id),
+        _index: this.getIndexForType(type),
+        _source: ['type', 'namespaces'],
+      }));
+    const bulkGetResponse = bulkGetDocs.length
+      ? await this._callCluster('mget', {
+          body: {
+            docs: bulkGetDocs,
+          },
+          ignore: [404],
+        })
+      : undefined;
+
+    let bulkRequestIndexCounter = 0;
+    const bulkCreateParams: object[] = [];
+    const expectedBulkResults: Either[] = expectedResults.map(expectedBulkGetResult => {
+      if (isLeft(expectedBulkGetResult)) {
+        return expectedBulkGetResult;
+      }
+
+      let savedObjectNamespace;
+      let savedObjectNamespaces;
+      const { esRequestIndex, object, method } = expectedBulkGetResult.value;
+      if (esRequestIndex !== undefined) {
+        const indexFound = bulkGetResponse.status !== 404;
+        const actualResult = indexFound ? bulkGetResponse.docs[esRequestIndex] : undefined;
+        const docFound = indexFound && actualResult.found === true;
+        if (docFound && !this.rawDocExistsInNamespace(actualResult, namespace)) {
+          const { id, type } = object;
+          return {
+            tag: 'Left' as 'Left',
+            error: {
+              id,
+              type,
+              error: SavedObjectsErrorHelpers.createConflictError(type, id).output.payload,
+            },
+          };
+        }
+        savedObjectNamespaces = getSavedObjectNamespaces(namespace, docFound && actualResult);
+      } else {
+        if (this._registry.isSingleNamespace(object.type)) {
+          savedObjectNamespace = namespace;
+        } else if (this._registry.isMultiNamespace(object.type)) {
+          savedObjectNamespaces = getSavedObjectNamespaces(namespace);
+        }
+      }
+
       const expectedResult = {
-        esRequestIndex: requestIndexCounter++,
+        esRequestIndex: bulkRequestIndexCounter++,
         requestedId: object.id,
         rawMigratedDoc: this._serializer.savedObjectToRaw(
           this._migrator.migrateDocument({
@@ -307,7 +378,8 @@ export class SavedObjectsRepository {
             type: object.type,
             attributes: object.attributes,
             migrationVersion: object.migrationVersion,
-            namespace,
+            ...(savedObjectNamespace && { namespace: savedObjectNamespace }),
+            ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }),
             updated_at: time,
             references: object.references || [],
           }) as SavedObjectSanitizedDoc
@@ -327,19 +399,21 @@ export class SavedObjectsRepository {
       return { tag: 'Right' as 'Right', value: expectedResult };
     });
 
-    const esResponse = await this._writeToCluster('bulk', {
-      refresh,
-      body: bulkCreateParams,
-    });
+    const bulkResponse = bulkCreateParams.length
+      ? await this._writeToCluster('bulk', {
+          refresh,
+          body: bulkCreateParams,
+        })
+      : undefined;
 
     return {
-      saved_objects: expectedResults.map(expectedResult => {
+      saved_objects: expectedBulkResults.map(expectedResult => {
         if (isLeft(expectedResult)) {
-          return expectedResult.error;
+          return expectedResult.error as any;
         }
 
         const { requestedId, rawMigratedDoc, esRequestIndex } = expectedResult.value;
-        const response = esResponse.items[esRequestIndex];
+        const response = bulkResponse.items[esRequestIndex];
         const {
           error,
           _id: responseId,
@@ -348,7 +422,7 @@ export class SavedObjectsRepository {
         } = Object.values(response)[0] as any;
 
         const {
-          _source: { type, [type]: attributes, references = [] },
+          _source: { type, [type]: attributes, references = [], namespaces },
         } = rawMigratedDoc;
 
         const id = requestedId || responseId;
@@ -362,6 +436,7 @@ export class SavedObjectsRepository {
         return {
           id,
           type,
+          ...(namespaces && { namespaces }),
           updated_at: time,
           version: encodeVersion(seqNo, primaryTerm),
           attributes,
@@ -382,32 +457,76 @@ export class SavedObjectsRepository {
    */
   async delete(type: string, id: string, options: SavedObjectsDeleteOptions = {}): Promise<{}> {
     if (!this._allowedTypes.includes(type)) {
-      throw SavedObjectsErrorHelpers.createGenericNotFoundError();
+      throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
     }
 
     const { namespace, refresh = DEFAULT_REFRESH_SETTING } = options;
 
-    const response = await this._writeToCluster('delete', {
-      id: this._serializer.generateRawId(namespace, type, id),
+    const rawId = this._serializer.generateRawId(namespace, type, id);
+    let preflightResult: SavedObjectsRawDoc | undefined;
+
+    if (this._registry.isMultiNamespace(type)) {
+      preflightResult = await this.preflightCheckIncludesNamespace(type, id, namespace);
+      const existingNamespaces = getSavedObjectNamespaces(undefined, preflightResult);
+      const remainingNamespaces = existingNamespaces?.filter(
+        x => x !== getNamespaceString(namespace)
+      );
+
+      if (remainingNamespaces?.length) {
+        // if there is 1 or more namespace remaining, update the saved object
+        const time = this._getCurrentTime();
+
+        const doc = {
+          updated_at: time,
+          namespaces: remainingNamespaces,
+        };
+
+        const updateResponse = await this._writeToCluster('update', {
+          id: rawId,
+          index: this.getIndexForType(type),
+          ...getExpectedVersionProperties(undefined, preflightResult),
+          refresh,
+          ignore: [404],
+          body: {
+            doc,
+          },
+        });
+
+        if (updateResponse.status === 404) {
+          // see "404s from missing index" above
+          throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+        }
+        return {};
+      }
+    }
+
+    const deleteResponse = await this._writeToCluster('delete', {
+      id: rawId,
       index: this.getIndexForType(type),
+      ...getExpectedVersionProperties(undefined, preflightResult),
       refresh,
       ignore: [404],
     });
 
-    const deleted = response.result === 'deleted';
+    const deleted = deleteResponse.result === 'deleted';
     if (deleted) {
       return {};
     }
 
-    const docNotFound = response.result === 'not_found';
-    const indexNotFound = response.error && response.error.type === 'index_not_found_exception';
-    if (docNotFound || indexNotFound) {
+    const deleteDocNotFound = deleteResponse.result === 'not_found';
+    const deleteIndexNotFound =
+      deleteResponse.error && deleteResponse.error.type === 'index_not_found_exception';
+    if (deleteDocNotFound || deleteIndexNotFound) {
       // see "404s from missing index" above
       throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
     }
 
     throw new Error(
-      `Unexpected Elasticsearch DELETE response: ${JSON.stringify({ type, id, response })}`
+      `Unexpected Elasticsearch DELETE response: ${JSON.stringify({
+        type,
+        id,
+        response: deleteResponse,
+      })}`
     );
   }
 
@@ -426,25 +545,37 @@ export class SavedObjectsRepository {
     }
 
     const { refresh = DEFAULT_REFRESH_SETTING } = options;
-
     const allTypes = Object.keys(getRootPropertiesObjects(this._mappings));
+    const typesToUpdate = allTypes.filter(type => !this._registry.isNamespaceAgnostic(type));
 
-    const typesToDelete = allTypes.filter(type => !this._registry.isNamespaceAgnostic(type));
-
-    const esOptions = {
-      index: this.getIndicesForTypes(typesToDelete),
+    const updateOptions = {
+      index: this.getIndicesForTypes(typesToUpdate),
       ignore: [404],
       refresh,
       body: {
+        script: {
+          source: `
+              if (!ctx._source.containsKey('namespaces')) {
+                ctx.op = "delete";
+              } else {
+                ctx._source['namespaces'].removeAll(Collections.singleton(params['namespace']));
+                if (ctx._source['namespaces'].empty) {
+                  ctx.op = "delete";
+                }
+              }
+            `,
+          lang: 'painless',
+          params: { namespace: getNamespaceString(namespace) },
+        },
         conflicts: 'proceed',
         ...getSearchDsl(this._mappings, this._registry, {
           namespace,
-          type: typesToDelete,
+          type: typesToUpdate,
         }),
       },
     };
 
-    return await this._writeToCluster('deleteByQuery', esOptions);
+    return await this._writeToCluster('updateByQuery', updateOptions);
   }
 
   /**
@@ -586,55 +717,77 @@ export class SavedObjectsRepository {
       return { saved_objects: [] };
     }
 
-    const unsupportedTypeObjects = objects
-      .filter(o => !this._allowedTypes.includes(o.type))
-      .map(({ type, id }) => {
-        return ({
-          id,
-          type,
-          error: SavedObjectsErrorHelpers.createUnsupportedTypeError(type).output.payload,
-        } as any) as SavedObject<T>;
-      });
+    let bulkGetRequestIndexCounter = 0;
+    const expectedBulkGetResults: Either[] = objects.map(object => {
+      const { type, id, fields } = object;
 
-    const supportedTypeObjects = objects.filter(o => this._allowedTypes.includes(o.type));
+      if (!this._allowedTypes.includes(type)) {
+        return {
+          tag: 'Left' as 'Left',
+          error: {
+            id,
+            type,
+            error: SavedObjectsErrorHelpers.createUnsupportedTypeError(type).output.payload,
+          },
+        };
+      }
 
-    const response = await this._callCluster('mget', {
-      body: {
-        docs: supportedTypeObjects.map(({ type, id, fields }) => {
-          return {
-            _id: this._serializer.generateRawId(namespace, type, id),
-            _index: this.getIndexForType(type),
-            _source: includedFields(type, fields),
-          };
-        }),
-      },
+      return {
+        tag: 'Right' as 'Right',
+        value: {
+          type,
+          id,
+          fields,
+          esRequestIndex: bulkGetRequestIndexCounter++,
+        },
+      };
     });
 
+    const bulkGetDocs = expectedBulkGetResults
+      .filter(isRight)
+      .map(({ value: { type, id, fields } }) => ({
+        _id: this._serializer.generateRawId(namespace, type, id),
+        _index: this.getIndexForType(type),
+        _source: includedFields(type, fields),
+      }));
+    const bulkGetResponse = bulkGetDocs.length
+      ? await this._callCluster('mget', {
+          body: {
+            docs: bulkGetDocs,
+          },
+          ignore: [404],
+        })
+      : undefined;
+
     return {
-      saved_objects: (response.docs as any[])
-        .map((doc, i) => {
-          const { id, type } = supportedTypeObjects[i];
+      saved_objects: expectedBulkGetResults.map(expectedResult => {
+        if (isLeft(expectedResult)) {
+          return expectedResult.error as any;
+        }
 
-          if (!doc.found) {
-            return ({
-              id,
-              type,
-              error: { statusCode: 404, message: 'Not found' },
-            } as any) as SavedObject<T>;
-          }
+        const { type, id, esRequestIndex } = expectedResult.value;
+        const doc = bulkGetResponse.docs[esRequestIndex];
 
-          const time = doc._source.updated_at;
-          return {
+        if (!doc.found || !this.rawDocExistsInNamespace(doc, namespace)) {
+          return ({
             id,
             type,
-            ...(time && { updated_at: time }),
-            version: encodeHitVersion(doc),
-            attributes: doc._source[type],
-            references: doc._source.references || [],
-            migrationVersion: doc._source.migrationVersion,
-          };
-        })
-        .concat(unsupportedTypeObjects),
+            error: SavedObjectsErrorHelpers.createGenericNotFoundError(type, id).output.payload,
+          } as any) as SavedObject<T>;
+        }
+
+        const time = doc._source.updated_at;
+        return {
+          id,
+          type,
+          ...(doc._source.namespaces && { namespaces: doc._source.namespaces }),
+          ...(time && { updated_at: time }),
+          version: encodeHitVersion(doc),
+          attributes: doc._source[type],
+          references: doc._source.references || [],
+          migrationVersion: doc._source.migrationVersion,
+        };
+      }),
     };
   }
 
@@ -666,7 +819,7 @@ export class SavedObjectsRepository {
 
     const docNotFound = response.found === false;
     const indexNotFound = response.status === 404;
-    if (docNotFound || indexNotFound) {
+    if (docNotFound || indexNotFound || !this.rawDocExistsInNamespace(response, namespace)) {
       // see "404s from missing index" above
       throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
     }
@@ -676,6 +829,7 @@ export class SavedObjectsRepository {
     return {
       id,
       type,
+      ...(response._source.namespaces && { namespaces: response._source.namespaces }),
       ...(updatedAt && { updated_at: updatedAt }),
       version: encodeHitVersion(response),
       attributes: response._source[type],
@@ -707,29 +861,32 @@ export class SavedObjectsRepository {
 
     const { version, namespace, references, refresh = DEFAULT_REFRESH_SETTING } = options;
 
+    let preflightResult: SavedObjectsRawDoc | undefined;
+    if (this._registry.isMultiNamespace(type)) {
+      preflightResult = await this.preflightCheckIncludesNamespace(type, id, namespace);
+    }
+
     const time = this._getCurrentTime();
 
     const doc = {
       [type]: attributes,
       updated_at: time,
-      references,
+      ...(Array.isArray(references) && { references }),
     };
-    if (!Array.isArray(doc.references)) {
-      delete doc.references;
-    }
 
-    const response = await this._writeToCluster('update', {
+    const updateResponse = await this._writeToCluster('update', {
       id: this._serializer.generateRawId(namespace, type, id),
       index: this.getIndexForType(type),
-      ...(version && decodeRequestVersion(version)),
+      ...getExpectedVersionProperties(version, preflightResult),
       refresh,
       ignore: [404],
       body: {
         doc,
       },
+      ...(this._registry.isMultiNamespace(type) && { _sourceIncludes: ['namespaces'] }),
     });
 
-    if (response.status === 404) {
+    if (updateResponse.status === 404) {
       // see "404s from missing index" above
       throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
     }
@@ -738,12 +895,168 @@ export class SavedObjectsRepository {
       id,
       type,
       updated_at: time,
-      version: encodeHitVersion(response),
+      version: encodeHitVersion(updateResponse),
+      ...(this._registry.isMultiNamespace(type) && {
+        namespaces: updateResponse.get._source.namespaces,
+      }),
       references,
       attributes,
     };
   }
 
+  /**
+   * Adds one or more namespaces to a given multi-namespace saved object. This method and
+   * [`deleteFromNamespaces`]{@link SavedObjectsRepository.deleteFromNamespaces} are the only ways to change which Spaces a multi-namespace
+   * saved object is shared to.
+   */
+  async addToNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsAddToNamespacesOptions = {}
+  ): Promise<{}> {
+    if (!this._allowedTypes.includes(type)) {
+      throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+    }
+
+    if (!this._registry.isMultiNamespace(type)) {
+      throw SavedObjectsErrorHelpers.createBadRequestError(
+        `${type} doesn't support multiple namespaces`
+      );
+    }
+
+    if (!namespaces.length) {
+      throw SavedObjectsErrorHelpers.createBadRequestError(
+        'namespaces must be a non-empty array of strings'
+      );
+    }
+
+    const { version, namespace, refresh = DEFAULT_REFRESH_SETTING } = options;
+
+    const rawId = this._serializer.generateRawId(undefined, type, id);
+    const preflightResult = await this.preflightCheckIncludesNamespace(type, id, namespace);
+    const existingNamespaces = getSavedObjectNamespaces(undefined, preflightResult);
+    // there should never be a case where a multi-namespace object does not have any existing namespaces
+    // however, it is a possibility if someone manually modifies the document in Elasticsearch
+    const time = this._getCurrentTime();
+
+    const doc = {
+      updated_at: time,
+      namespaces: existingNamespaces ? unique(existingNamespaces.concat(namespaces)) : namespaces,
+    };
+
+    const updateResponse = await this._writeToCluster('update', {
+      id: rawId,
+      index: this.getIndexForType(type),
+      ...getExpectedVersionProperties(version, preflightResult),
+      refresh,
+      ignore: [404],
+      body: {
+        doc,
+      },
+    });
+
+    if (updateResponse.status === 404) {
+      // see "404s from missing index" above
+      throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+    }
+
+    return {};
+  }
+
+  /**
+   * Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted
+   * entirely. This method and [`addToNamespaces`]{@link SavedObjectsRepository.addToNamespaces} are the only ways to change which Spaces a
+   * multi-namespace saved object is shared to.
+   */
+  async deleteFromNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsDeleteFromNamespacesOptions = {}
+  ): Promise<{}> {
+    if (!this._allowedTypes.includes(type)) {
+      throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+    }
+
+    if (!this._registry.isMultiNamespace(type)) {
+      throw SavedObjectsErrorHelpers.createBadRequestError(
+        `${type} doesn't support multiple namespaces`
+      );
+    }
+
+    if (!namespaces.length) {
+      throw SavedObjectsErrorHelpers.createBadRequestError(
+        'namespaces must be a non-empty array of strings'
+      );
+    }
+
+    const { namespace, refresh = DEFAULT_REFRESH_SETTING } = options;
+
+    const rawId = this._serializer.generateRawId(undefined, type, id);
+    const preflightResult = await this.preflightCheckIncludesNamespace(type, id, namespace);
+    const existingNamespaces = getSavedObjectNamespaces(undefined, preflightResult);
+    // if there are somehow no existing namespaces, allow the operation to proceed and delete this saved object
+    const remainingNamespaces = existingNamespaces?.filter(x => !namespaces.includes(x));
+
+    if (remainingNamespaces?.length) {
+      // if there is 1 or more namespace remaining, update the saved object
+      const time = this._getCurrentTime();
+
+      const doc = {
+        updated_at: time,
+        namespaces: remainingNamespaces,
+      };
+
+      const updateResponse = await this._writeToCluster('update', {
+        id: rawId,
+        index: this.getIndexForType(type),
+        ...getExpectedVersionProperties(undefined, preflightResult),
+        refresh,
+        ignore: [404],
+        body: {
+          doc,
+        },
+      });
+
+      if (updateResponse.status === 404) {
+        // see "404s from missing index" above
+        throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+      }
+      return {};
+    } else {
+      // if there are no namespaces remaining, delete the saved object
+      const deleteResponse = await this._writeToCluster('delete', {
+        id: this._serializer.generateRawId(undefined, type, id),
+        index: this.getIndexForType(type),
+        ...getExpectedVersionProperties(undefined, preflightResult),
+        refresh,
+        ignore: [404],
+      });
+
+      const deleted = deleteResponse.result === 'deleted';
+      if (deleted) {
+        return {};
+      }
+
+      const deleteDocNotFound = deleteResponse.result === 'not_found';
+      const deleteIndexNotFound =
+        deleteResponse.error && deleteResponse.error.type === 'index_not_found_exception';
+      if (deleteDocNotFound || deleteIndexNotFound) {
+        // see "404s from missing index" above
+        throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+      }
+
+      throw new Error(
+        `Unexpected Elasticsearch DELETE response: ${JSON.stringify({
+          type,
+          id,
+          response: deleteResponse,
+        })}`
+      );
+    }
+  }
+
   /**
    * Updates multiple objects in bulk
    *
@@ -757,10 +1070,10 @@ export class SavedObjectsRepository {
     options: SavedObjectsBulkUpdateOptions = {}
   ): Promise<SavedObjectsBulkUpdateResponse<T>> {
     const time = this._getCurrentTime();
-    const bulkUpdateParams: object[] = [];
+    const { namespace } = options;
 
-    let requestIndexCounter = 0;
-    const expectedResults: Array<Either<any, any>> = objects.map(object => {
+    let bulkGetRequestIndexCounter = 0;
+    const expectedBulkGetResults: Either[] = objects.map(object => {
       const { type, id } = object;
 
       if (!this._allowedTypes.includes(type)) {
@@ -775,41 +1088,100 @@ export class SavedObjectsRepository {
       }
 
       const { attributes, references, version } = object;
-      const { namespace } = options;
 
       const documentToSave = {
         [type]: attributes,
         updated_at: time,
-        references,
+        ...(Array.isArray(references) && { references }),
       };
 
-      if (!Array.isArray(documentToSave.references)) {
-        delete documentToSave.references;
-      }
+      const requiresNamespacesCheck = this._registry.isMultiNamespace(object.type);
 
-      const expectedResult = {
-        type,
-        id,
-        esRequestIndex: requestIndexCounter++,
-        documentToSave,
+      return {
+        tag: 'Right' as 'Right',
+        value: {
+          type,
+          id,
+          version,
+          documentToSave,
+          ...(requiresNamespacesCheck && { esRequestIndex: bulkGetRequestIndexCounter++ }),
+        },
       };
+    });
 
-      bulkUpdateParams.push(
-        {
-          update: {
-            _id: this._serializer.generateRawId(namespace, type, id),
-            _index: this.getIndexForType(type),
-            ...(version && decodeRequestVersion(version)),
+    const bulkGetDocs = expectedBulkGetResults
+      .filter(isRight)
+      .filter(({ value }) => value.esRequestIndex !== undefined)
+      .map(({ value: { type, id } }) => ({
+        _id: this._serializer.generateRawId(namespace, type, id),
+        _index: this.getIndexForType(type),
+        _source: ['type', 'namespaces'],
+      }));
+    const bulkGetResponse = bulkGetDocs.length
+      ? await this._callCluster('mget', {
+          body: {
+            docs: bulkGetDocs,
           },
-        },
-        { doc: documentToSave }
-      );
+          ignore: [404],
+        })
+      : undefined;
 
-      return { tag: 'Right' as 'Right', value: expectedResult };
-    });
+    let bulkUpdateRequestIndexCounter = 0;
+    const bulkUpdateParams: object[] = [];
+    const expectedBulkUpdateResults: Either[] = expectedBulkGetResults.map(
+      expectedBulkGetResult => {
+        if (isLeft(expectedBulkGetResult)) {
+          return expectedBulkGetResult;
+        }
+
+        const { esRequestIndex, id, type, version, documentToSave } = expectedBulkGetResult.value;
+        let namespaces;
+        let versionProperties;
+        if (esRequestIndex !== undefined) {
+          const indexFound = bulkGetResponse.status !== 404;
+          const actualResult = indexFound ? bulkGetResponse.docs[esRequestIndex] : undefined;
+          const docFound = indexFound && actualResult.found === true;
+          if (!docFound || !this.rawDocExistsInNamespace(actualResult, namespace)) {
+            return {
+              tag: 'Left' as 'Left',
+              error: {
+                id,
+                type,
+                error: SavedObjectsErrorHelpers.createGenericNotFoundError(type, id).output.payload,
+              },
+            };
+          }
+          namespaces = actualResult._source.namespaces;
+          versionProperties = getExpectedVersionProperties(version, actualResult);
+        } else {
+          versionProperties = getExpectedVersionProperties(version);
+        }
+
+        const expectedResult = {
+          type,
+          id,
+          namespaces,
+          esRequestIndex: bulkUpdateRequestIndexCounter++,
+          documentToSave: expectedBulkGetResult.value.documentToSave,
+        };
+
+        bulkUpdateParams.push(
+          {
+            update: {
+              _id: this._serializer.generateRawId(namespace, type, id),
+              _index: this.getIndexForType(type),
+              ...versionProperties,
+            },
+          },
+          { doc: documentToSave }
+        );
+
+        return { tag: 'Right' as 'Right', value: expectedResult };
+      }
+    );
 
     const { refresh = DEFAULT_REFRESH_SETTING } = options;
-    const esResponse = bulkUpdateParams.length
+    const bulkUpdateResponse = bulkUpdateParams.length
       ? await this._writeToCluster('bulk', {
           refresh,
           body: bulkUpdateParams,
@@ -817,13 +1189,13 @@ export class SavedObjectsRepository {
       : {};
 
     return {
-      saved_objects: expectedResults.map(expectedResult => {
+      saved_objects: expectedBulkUpdateResults.map(expectedResult => {
         if (isLeft(expectedResult)) {
-          return expectedResult.error;
+          return expectedResult.error as any;
         }
 
-        const { type, id, documentToSave, esRequestIndex } = expectedResult.value;
-        const response = esResponse.items[esRequestIndex];
+        const { type, id, namespaces, documentToSave, esRequestIndex } = expectedResult.value;
+        const response = bulkUpdateResponse.items[esRequestIndex];
         const { error, _seq_no: seqNo, _primary_term: primaryTerm } = Object.values(
           response
         )[0] as any;
@@ -839,6 +1211,7 @@ export class SavedObjectsRepository {
         return {
           id,
           type,
+          ...(namespaces && { namespaces }),
           updated_at,
           version: encodeVersion(seqNo, primaryTerm),
           attributes,
@@ -877,10 +1250,20 @@ export class SavedObjectsRepository {
     const { migrationVersion, namespace, refresh = DEFAULT_REFRESH_SETTING } = options;
 
     const time = this._getCurrentTime();
+    let savedObjectNamespace;
+    let savedObjectNamespaces: string[] | undefined;
+
+    if (this._registry.isSingleNamespace(type) && namespace) {
+      savedObjectNamespace = namespace;
+    } else if (this._registry.isMultiNamespace(type)) {
+      savedObjectNamespaces = await this.preflightGetNamespaces(type, id, namespace);
+    }
 
     const migrated = this._migrator.migrateDocument({
       id,
       type,
+      ...(savedObjectNamespace && { namespace: savedObjectNamespace }),
+      ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }),
       attributes: { [counterFieldName]: 1 },
       migrationVersion,
       updated_at: time,
@@ -889,7 +1272,7 @@ export class SavedObjectsRepository {
     const raw = this._serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc);
 
     const response = await this._writeToCluster('update', {
-      id: this._serializer.generateRawId(namespace, type, id),
+      id: raw._id,
       index: this.getIndexForType(type),
       refresh,
       _source: true,
@@ -952,14 +1335,13 @@ export class SavedObjectsRepository {
   }
 
   /**
-   * Returns an array of indices as specified in `this._schema` for each of the
+   * Returns an array of indices as specified in `this._registry` for each of the
    * given `types`. If any of the types don't have an associated index, the
    * default index `this._index` will be included.
    *
    * @param types The types whose indices should be retrieved
    */
   private getIndicesForTypes(types: string[]) {
-    const unique = (array: string[]) => [...new Set(array)];
     return unique(types.map(t => this.getIndexForType(t)));
   }
 
@@ -975,12 +1357,97 @@ export class SavedObjectsRepository {
     const savedObject = this._serializer.rawToSavedObject(raw);
     return omit(savedObject, 'namespace');
   }
+
+  /**
+   * Check to ensure that a raw document exists in a namespace. If the document is not a multi-namespace type, then this returns `true` as
+   * we rely on the guarantees of the document ID format. If the document is a multi-namespace type, this checks to ensure that the
+   * document's `namespaces` value includes the string representation of the given namespace.
+   *
+   * WARNING: This should only be used for documents that were retrieved from Elasticsearch. Otherwise, the guarantees of the document ID
+   * format mentioned above do not apply.
+   */
+  private rawDocExistsInNamespace(raw: SavedObjectsRawDoc, namespace?: string) {
+    const rawDocType = raw._source.type;
+
+    // if the type is namespace isolated, or namespace agnostic, we can continue to rely on the guarantees
+    // of the document ID format and don't need to check this
+    if (!this._registry.isMultiNamespace(rawDocType)) {
+      return true;
+    }
+
+    const namespaces = raw._source.namespaces;
+    return namespaces?.includes(getNamespaceString(namespace)) ?? false;
+  }
+
+  /**
+   * Pre-flight check to get a multi-namespace saved object's included namespaces. This ensures that, if the saved object exists, it
+   * includes the target namespace.
+   *
+   * @param type The type of the saved object.
+   * @param id The ID of the saved object.
+   * @param namespace The target namespace.
+   * @returns Array of namespaces that this saved object currently includes, or (if the object does not exist yet) the namespaces that a
+   * newly-created object will include. Value may be undefined if an existing saved object has no namespaces attribute; this should not
+   * happen in normal operations, but it is possible if the Elasticsearch document is manually modified.
+   * @throws Will throw an error if the saved object exists and it does not include the target namespace.
+   */
+  private async preflightGetNamespaces(type: string, id: string, namespace?: string) {
+    if (!this._registry.isMultiNamespace(type)) {
+      throw new Error(`Cannot make preflight get request for non-multi-namespace type '${type}'.`);
+    }
+
+    const response = await this._callCluster('get', {
+      id: this._serializer.generateRawId(undefined, type, id),
+      index: this.getIndexForType(type),
+      ignore: [404],
+    });
+
+    const indexFound = response.status !== 404;
+    const docFound = indexFound && response.found === true;
+    if (docFound) {
+      if (!this.rawDocExistsInNamespace(response, namespace)) {
+        throw SavedObjectsErrorHelpers.createConflictError(type, id);
+      }
+      return getSavedObjectNamespaces(namespace, response);
+    }
+    return getSavedObjectNamespaces(namespace);
+  }
+
+  /**
+   * Pre-flight check for a multi-namespace saved object's namespaces. This ensures that, if the saved object exists, it includes the target
+   * namespace.
+   *
+   * @param type The type of the saved object.
+   * @param id The ID of the saved object.
+   * @param namespace The target namespace.
+   * @returns Raw document from Elasticsearch.
+   * @throws Will throw an error if the saved object is not found, or if it doesn't include the target namespace.
+   */
+  private async preflightCheckIncludesNamespace(type: string, id: string, namespace?: string) {
+    if (!this._registry.isMultiNamespace(type)) {
+      throw new Error(`Cannot make preflight get request for non-multi-namespace type '${type}'.`);
+    }
+
+    const rawId = this._serializer.generateRawId(undefined, type, id);
+    const response = await this._callCluster('get', {
+      id: rawId,
+      index: this.getIndexForType(type),
+      ignore: [404],
+    });
+
+    const indexFound = response.status !== 404;
+    const docFound = indexFound && response.found === true;
+    if (!docFound || !this.rawDocExistsInNamespace(response, namespace)) {
+      throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+    }
+    return response as SavedObjectsRawDoc;
+  }
 }
 
 function getBulkOperationError(error: { type: string; reason?: string }, type: string, id: string) {
   switch (error.type) {
     case 'version_conflict_engine_exception':
-      return { statusCode: 409, message: 'version conflict, document already exists' };
+      return SavedObjectsErrorHelpers.createConflictError(type, id).output.payload;
     case 'document_missing_exception':
       return SavedObjectsErrorHelpers.createGenericNotFoundError(type, id).output.payload;
     default:
@@ -989,3 +1456,49 @@ function getBulkOperationError(error: { type: string; reason?: string }, type: s
       };
   }
 }
+
+/**
+ * Returns an object with the expected version properties. This facilitates Elasticsearch's Optimistic Concurrency Control.
+ *
+ * @param version Optional version specified by the consumer.
+ * @param document Optional existing document that was obtained in a preflight operation.
+ */
+function getExpectedVersionProperties(version?: string, document?: SavedObjectsRawDoc) {
+  if (version) {
+    return decodeRequestVersion(version);
+  } else if (document) {
+    return {
+      if_seq_no: document._seq_no,
+      if_primary_term: document._primary_term,
+    };
+  }
+  return {};
+}
+
+/**
+ * Returns the string representation of a namespace.
+ * The default namespace is undefined, and is represented by the string 'default'.
+ */
+function getNamespaceString(namespace?: string) {
+  return namespace ?? 'default';
+}
+
+/**
+ * Returns a string array of namespaces for a given saved object. If the saved object is undefined, the result is an array that contains the
+ * current namespace. Value may be undefined if an existing saved object has no namespaces attribute; this should not happen in normal
+ * operations, but it is possible if the Elasticsearch document is manually modified.
+ *
+ * @param namespace The current namespace.
+ * @param document Optional existing saved object that was obtained in a preflight operation.
+ */
+function getSavedObjectNamespaces(
+  namespace?: string,
+  document?: SavedObjectsRawDoc
+): string[] | undefined {
+  if (document) {
+    return document._source?.namespaces;
+  }
+  return [getNamespaceString(namespace)];
+}
+
+const unique = (array: string[]) => [...new Set(array)];
diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts
index b2129765ee426..a72c21dd5eee4 100644
--- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts
+++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts
@@ -17,6 +17,9 @@
  * under the License.
  */
 
+// eslint-disable-next-line @kbn/eslint/no-restricted-paths
+import { esKuery, KueryNode } from '../../../../../../plugins/data/server';
+
 import { typeRegistryMock } from '../../../saved_objects_type_registry.mock';
 import { getQueryParams } from './query_params';
 
@@ -24,1268 +27,329 @@ const registry = typeRegistryMock.create();
 
 const MAPPINGS = {
   properties: {
-    type: {
-      type: 'keyword',
-    },
-    pending: {
-      properties: {
-        title: {
-          type: 'text',
-        },
-      },
-    },
+    pending: { properties: { title: { type: 'text' } } },
     saved: {
       properties: {
-        title: {
-          type: 'text',
-          fields: {
-            raw: {
-              type: 'keyword',
-            },
-          },
-        },
-        obj: {
-          properties: {
-            key1: {
-              type: 'text',
-            },
-          },
-        },
-      },
-    },
-    global: {
-      properties: {
-        name: {
-          type: 'keyword',
-        },
+        title: { type: 'text', fields: { raw: { type: 'keyword' } } },
+        obj: { properties: { key1: { type: 'text' } } },
       },
     },
+    // mock registry returns isMultiNamespace=true for 'shared' type
+    shared: { properties: { name: { type: 'keyword' } } },
+    // mock registry returns isNamespaceAgnostic=true for 'global' type
+    global: { properties: { name: { type: 'keyword' } } },
   },
 };
+const ALL_TYPES = Object.keys(MAPPINGS.properties);
+// get all possible subsets (combination) of all types
+const ALL_TYPE_SUBSETS = ALL_TYPES.reduce(
+  (subsets, value) => subsets.concat(subsets.map(set => [...set, value])),
+  [[] as string[]]
+)
+  .filter(x => x.length) // exclude empty set
+  .map(x => (x.length === 1 ? x[0] : x)); // if a subset is a single string, destructure it
 
-// create a type clause to be used within the "should", if a namespace is specified
-// the clause will ensure the namespace matches; otherwise, the clause will ensure
-// that there isn't a namespace field.
-const createTypeClause = (type: string, namespace?: string) => {
-  if (namespace) {
-    return {
-      bool: {
-        must: [{ term: { type } }, { term: { namespace } }],
-      },
-    };
-  }
+/**
+ * Note: these tests cases are defined in the order they appear in the source code, for readability's sake
+ */
+describe('#getQueryParams', () => {
+  const mappings = MAPPINGS;
+  type Result = ReturnType<typeof getQueryParams>;
 
-  return {
-    bool: {
-      must: [{ term: { type } }],
-      must_not: [{ exists: { field: 'namespace' } }],
-    },
-  };
-};
+  describe('kueryNode filter clause (query.bool.filter[...]', () => {
+    const expectResult = (result: Result, expected: any) => {
+      expect(result.query.bool.filter).toEqual(expect.arrayContaining([expected]));
+    };
 
-describe('searchDsl/queryParams', () => {
-  describe('no parameters', () => {
-    it('searches for all known types without a namespace specified', () => {
-      expect(getQueryParams({ mappings: MAPPINGS, registry })).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending'),
-                    createTypeClause('saved'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
+    describe('`kueryNode` parameter', () => {
+      it('does not include the clause when `kueryNode` is not specified', () => {
+        const result = getQueryParams({ mappings, registry, kueryNode: undefined });
+        expect(result.query.bool.filter).toHaveLength(1);
       });
-    });
-  });
 
-  describe('namespace', () => {
-    it('filters namespaced types for namespace, and ensures namespace agnostic types have no namespace', () => {
-      expect(getQueryParams({ mappings: MAPPINGS, registry, namespace: 'foo-namespace' })).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending', 'foo-namespace'),
-                    createTypeClause('saved', 'foo-namespace'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-  });
+      it('includes the specified Kuery clause', () => {
+        const test = (kueryNode: KueryNode) => {
+          const result = getQueryParams({ mappings, registry, kueryNode });
+          const expected = esKuery.toElasticsearchQuery(kueryNode);
+          expect(result.query.bool.filter).toHaveLength(2);
+          expectResult(result, expected);
+        };
 
-  describe('type (singular, namespaced)', () => {
-    it('includes a terms filter for type and namespace not being specified', () => {
-      expect(
-        getQueryParams({ mappings: MAPPINGS, registry, namespace: undefined, type: 'saved' })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-  });
+        const simpleClause = {
+          type: 'function',
+          function: 'is',
+          arguments: [
+            { type: 'literal', value: 'global.name' },
+            { type: 'literal', value: 'GLOBAL' },
+            { type: 'literal', value: false },
+          ],
+        } as KueryNode;
+        test(simpleClause);
 
-  describe('type (singular, global)', () => {
-    it('includes a terms filter for type and namespace not being specified', () => {
-      expect(
-        getQueryParams({ mappings: MAPPINGS, registry, namespace: undefined, type: 'global' })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('global')],
-                  minimum_should_match: 1,
+        const complexClause = {
+          type: 'function',
+          function: 'and',
+          arguments: [
+            simpleClause,
+            {
+              type: 'function',
+              function: 'not',
+              arguments: [
+                {
+                  type: 'function',
+                  function: 'is',
+                  arguments: [
+                    { type: 'literal', value: 'saved.obj.key1' },
+                    { type: 'literal', value: 'key' },
+                    { type: 'literal', value: true },
+                  ],
                 },
-              },
-            ],
-          },
-        },
+              ],
+            },
+          ],
+        } as KueryNode;
+        test(complexClause);
       });
     });
   });
 
-  describe('type (plural, namespaced and global)', () => {
-    it('includes term filters for types and namespace not being specified', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: ['saved', 'global'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-  });
+  describe('reference filter clause (query.bool.filter[bool.must])', () => {
+    describe('`hasReference` parameter', () => {
+      const expectResult = (result: Result, expected: any) => {
+        expect(result.query.bool.filter).toEqual(
+          expect.arrayContaining([{ bool: expect.objectContaining({ must: expected }) }])
+        );
+      };
 
-  describe('namespace, type (plural, namespaced and global)', () => {
-    it('includes a terms filter for type and namespace not being specified', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+      it('does not include the clause when `hasReference` is not specified', () => {
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved', 'foo-namespace'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
+          hasReference: undefined,
+        });
+        expectResult(result, undefined);
       });
-    });
-  });
 
-  describe('search', () => {
-    it('includes a sqs query and all known types without a namespace specified', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+      it('creates a clause with query for specified reference', () => {
+        const hasReference = { id: 'foo', type: 'bar' };
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: undefined,
-          type: undefined,
-          search: 'us*',
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
+          hasReference,
+        });
+        expectResult(result, [
+          {
+            nested: {
+              path: 'references',
+              query: {
                 bool: {
-                  should: [
-                    createTypeClause('pending'),
-                    createTypeClause('saved'),
-                    createTypeClause('global'),
+                  must: [
+                    { term: { 'references.id': hasReference.id } },
+                    { term: { 'references.type': hasReference.type } },
                   ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'us*',
-                  lenient: true,
-                  fields: ['*'],
                 },
               },
-            ],
+            },
           },
-        },
+        ]);
       });
     });
   });
 
-  describe('namespace, search', () => {
-    it('includes a sqs query and namespaced types with the namespace and global types without a namespace', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: undefined,
-          search: 'us*',
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending', 'foo-namespace'),
-                    createTypeClause('saved', 'foo-namespace'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'us*',
-                  lenient: true,
-                  fields: ['*'],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-  });
+  describe('type filter clauses (query.bool.filter[bool.should])', () => {
+    describe('`type` parameter', () => {
+      const expectResult = (result: Result, ...types: string[]) => {
+        expect(result.query.bool.filter).toEqual(
+          expect.arrayContaining([
+            {
+              bool: expect.objectContaining({
+                should: types.map(type => ({
+                  bool: expect.objectContaining({
+                    must: expect.arrayContaining([{ term: { type } }]),
+                  }),
+                })),
+                minimum_should_match: 1,
+              }),
+            },
+          ])
+        );
+      };
 
-  describe('type (plural, namespaced and global), search', () => {
-    it('includes a sqs query and types without a namespace', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: ['saved', 'global'],
-          search: 'us*',
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'us*',
-                  lenient: true,
-                  fields: ['*'],
-                },
-              },
-            ],
-          },
-        },
+      it('searches for all known types when `type` is not specified', () => {
+        const result = getQueryParams({ mappings, registry, type: undefined });
+        expectResult(result, ...ALL_TYPES);
       });
-    });
-  });
 
-  describe('namespace, type (plural, namespaced and global), search', () => {
-    it('includes a sqs query and namespace type with a namespace and global type without a namespace', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-          search: 'us*',
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved', 'foo-namespace'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'us*',
-                  lenient: true,
-                  fields: ['*'],
-                },
-              },
-            ],
-          },
-        },
+      it('searches for specified type/s', () => {
+        const test = (typeOrTypes: string | string[]) => {
+          const result = getQueryParams({
+            mappings,
+            registry,
+            type: typeOrTypes,
+          });
+          const type = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
+          expectResult(result, ...type);
+        };
+        for (const typeOrTypes of ALL_TYPE_SUBSETS) {
+          test(typeOrTypes);
+        }
       });
     });
-  });
 
-  describe('search, searchFields', () => {
-    it('includes all types for field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: undefined,
-          search: 'y*',
-          searchFields: ['title'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending'),
-                    createTypeClause('saved'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['pending.title', 'saved.title', 'global.title'],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-    it('supports field boosting', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: undefined,
-          search: 'y*',
-          searchFields: ['title^3'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending'),
-                    createTypeClause('saved'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['pending.title^3', 'saved.title^3', 'global.title^3'],
-                },
-              },
-            ],
-          },
-        },
+    describe('`namespace` parameter', () => {
+      const createTypeClause = (type: string, namespace?: string) => {
+        if (registry.isMultiNamespace(type)) {
+          return {
+            bool: {
+              must: expect.arrayContaining([{ term: { namespaces: namespace ?? 'default' } }]),
+              must_not: [{ exists: { field: 'namespace' } }],
+            },
+          };
+        } else if (namespace && registry.isSingleNamespace(type)) {
+          return {
+            bool: {
+              must: expect.arrayContaining([{ term: { namespace } }]),
+              must_not: [{ exists: { field: 'namespaces' } }],
+            },
+          };
+        }
+        // isNamespaceAgnostic
+        return {
+          bool: expect.objectContaining({
+            must_not: [{ exists: { field: 'namespace' } }, { exists: { field: 'namespaces' } }],
+          }),
+        };
+      };
+
+      const expectResult = (result: Result, ...typeClauses: any) => {
+        expect(result.query.bool.filter).toEqual(
+          expect.arrayContaining([
+            { bool: expect.objectContaining({ should: typeClauses, minimum_should_match: 1 }) },
+          ])
+        );
+      };
+
+      const test = (namespace?: string) => {
+        for (const typeOrTypes of ALL_TYPE_SUBSETS) {
+          const result = getQueryParams({ mappings, registry, type: typeOrTypes, namespace });
+          const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
+          expectResult(result, ...types.map(x => createTypeClause(x, namespace)));
+        }
+        // also test with no specified type/s
+        const result = getQueryParams({ mappings, registry, type: undefined, namespace });
+        expectResult(result, ...ALL_TYPES.map(x => createTypeClause(x, namespace)));
+      };
+
+      it('filters results with "namespace" field when `namespace` is not specified', () => {
+        test(undefined);
       });
-    });
-    it('supports field and multi-field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: undefined,
-          search: 'y*',
-          searchFields: ['title', 'title.raw'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending'),
-                    createTypeClause('saved'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: [
-                    'pending.title',
-                    'saved.title',
-                    'global.title',
-                    'pending.title.raw',
-                    'saved.title.raw',
-                    'global.title.raw',
-                  ],
-                },
-              },
-            ],
-          },
-        },
+
+      it('filters results for specified namespace for appropriate type/s', () => {
+        test('foo-namespace');
       });
     });
   });
 
-  describe('namespace, search, searchFields', () => {
-    it('includes all types for field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+  describe('search clause (query.bool.must.simple_query_string)', () => {
+    const search = 'foo*';
+
+    const expectResult = (result: Result, sqsClause: any) => {
+      expect(result.query.bool.must).toEqual([{ simple_query_string: sqsClause }]);
+    };
+
+    describe('`search` parameter', () => {
+      it('does not include clause when `search` is not specified', () => {
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: 'foo-namespace',
-          type: undefined,
-          search: 'y*',
-          searchFields: ['title'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending', 'foo-namespace'),
-                    createTypeClause('saved', 'foo-namespace'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['pending.title', 'saved.title', 'global.title'],
-                },
-              },
-            ],
-          },
-        },
+          search: undefined,
+        });
+        expect(result.query.bool.must).toBeUndefined();
       });
-    });
-    it('supports field boosting', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+
+      it('creates a clause with query for specified search', () => {
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: 'foo-namespace',
-          type: undefined,
-          search: 'y*',
-          searchFields: ['title^3'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending', 'foo-namespace'),
-                    createTypeClause('saved', 'foo-namespace'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['pending.title^3', 'saved.title^3', 'global.title^3'],
-                },
-              },
-            ],
-          },
-        },
+          search,
+        });
+        expectResult(result, expect.objectContaining({ query: search }));
       });
     });
-    it('supports field and multi-field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+
+    describe('`searchFields` parameter', () => {
+      const getExpectedFields = (searchFields: string[], typeOrTypes: string | string[]) => {
+        const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
+        return searchFields.map(x => types.map(y => `${y}.${x}`)).flat();
+      };
+
+      const test = (searchFields: string[]) => {
+        for (const typeOrTypes of ALL_TYPE_SUBSETS) {
+          const result = getQueryParams({
+            mappings,
+            registry,
+            type: typeOrTypes,
+            search,
+            searchFields,
+          });
+          const fields = getExpectedFields(searchFields, typeOrTypes);
+          expectResult(result, expect.objectContaining({ fields }));
+        }
+        // also test with no specified type/s
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: 'foo-namespace',
           type: undefined,
-          search: 'y*',
-          searchFields: ['title', 'title.raw'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    createTypeClause('pending', 'foo-namespace'),
-                    createTypeClause('saved', 'foo-namespace'),
-                    createTypeClause('global'),
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: [
-                    'pending.title',
-                    'saved.title',
-                    'global.title',
-                    'pending.title.raw',
-                    'saved.title.raw',
-                    'global.title.raw',
-                  ],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-  });
+          search,
+          searchFields,
+        });
+        const fields = getExpectedFields(searchFields, ALL_TYPES);
+        expectResult(result, expect.objectContaining({ fields }));
+      };
 
-  describe('type (plural, namespaced and global), search, searchFields', () => {
-    it('includes all types for field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: ['saved', 'global'],
-          search: 'y*',
-          searchFields: ['title'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['saved.title', 'global.title'],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-    it('supports field boosting', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: undefined,
-          type: ['saved', 'global'],
-          search: 'y*',
-          searchFields: ['title^3'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['saved.title^3', 'global.title^3'],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-    it('supports field and multi-field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+      it('includes lenient flag and all fields when `searchFields` is not specified', () => {
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: undefined,
-          type: ['saved', 'global'],
-          search: 'y*',
-          searchFields: ['title', 'title.raw'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['saved.title', 'global.title', 'saved.title.raw', 'global.title.raw'],
-                },
-              },
-            ],
-          },
-        },
+          search,
+          searchFields: undefined,
+        });
+        expectResult(result, expect.objectContaining({ lenient: true, fields: ['*'] }));
       });
-    });
-  });
 
-  describe('namespace, type (plural, namespaced and global), search, searchFields', () => {
-    it('includes all types for field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-          search: 'y*',
-          searchFields: ['title'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved', 'foo-namespace'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['saved.title', 'global.title'],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-    it('supports field boosting', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-          search: 'y*',
-          searchFields: ['title^3'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved', 'foo-namespace'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['saved.title^3', 'global.title^3'],
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-    it('supports field and multi-field', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-          search: 'y*',
-          searchFields: ['title', 'title.raw'],
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [createTypeClause('saved', 'foo-namespace'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['saved.title', 'global.title', 'saved.title.raw', 'global.title.raw'],
-                },
-              },
-            ],
-          },
-        },
+      it('includes specified search fields for appropriate type/s', () => {
+        test(['title']);
       });
-    });
-  });
 
-  describe('type (plural, namespaced and global), search, defaultSearchOperator', () => {
-    it('supports defaultSearchOperator', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-          search: 'foo',
-          searchFields: undefined,
-          defaultSearchOperator: 'AND',
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  minimum_should_match: 1,
-                  should: [
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'saved',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'global',
-                            },
-                          },
-                        ],
-                        must_not: [
-                          {
-                            exists: {
-                              field: 'namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                  ],
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  lenient: true,
-                  fields: ['*'],
-                  default_operator: 'AND',
-                  query: 'foo',
-                },
-              },
-            ],
-          },
-        },
+      it('supports boosting', () => {
+        test(['title^3']);
       });
-    });
-  });
 
-  describe('type (plural, namespaced and global), hasReference', () => {
-    it('supports hasReference', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          type: ['saved', 'global'],
-          search: undefined,
-          searchFields: undefined,
-          defaultSearchOperator: 'OR',
-          hasReference: {
-            type: 'bar',
-            id: '1',
-          },
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  must: [
-                    {
-                      nested: {
-                        path: 'references',
-                        query: {
-                          bool: {
-                            must: [
-                              {
-                                term: {
-                                  'references.id': '1',
-                                },
-                              },
-                              {
-                                term: {
-                                  'references.type': 'bar',
-                                },
-                              },
-                            ],
-                          },
-                        },
-                      },
-                    },
-                  ],
-                  should: [createTypeClause('saved', 'foo-namespace'), createTypeClause('global')],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
+      it('supports multiple fields', () => {
+        test(['title, title.raw']);
       });
     });
-  });
 
-  describe('type filter', () => {
-    it(' with namespace', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
-          registry,
-          namespace: 'foo-namespace',
-          kueryNode: {
-            type: 'function',
-            function: 'is',
-            arguments: [
-              { type: 'literal', value: 'global.name' },
-              { type: 'literal', value: 'GLOBAL' },
-              { type: 'literal', value: false },
-            ],
-          },
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    {
-                      match: {
-                        'global.name': 'GLOBAL',
-                      },
-                    },
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-              {
-                bool: {
-                  should: [
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'pending',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'saved',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'global',
-                            },
-                          },
-                        ],
-                        must_not: [
-                          {
-                            exists: {
-                              field: 'namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
-      });
-    });
-    it(' with namespace and more complex filter', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+    describe('`defaultSearchOperator` parameter', () => {
+      it('does not include default_operator when `defaultSearchOperator` is not specified', () => {
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: 'foo-namespace',
-          kueryNode: {
-            type: 'function',
-            function: 'and',
-            arguments: [
-              {
-                type: 'function',
-                function: 'is',
-                arguments: [
-                  { type: 'literal', value: 'global.name' },
-                  { type: 'literal', value: 'GLOBAL' },
-                  { type: 'literal', value: false },
-                ],
-              },
-              {
-                type: 'function',
-                function: 'not',
-                arguments: [
-                  {
-                    type: 'function',
-                    function: 'is',
-                    arguments: [
-                      { type: 'literal', value: 'saved.obj.key1' },
-                      { type: 'literal', value: 'key' },
-                      { type: 'literal', value: true },
-                    ],
-                  },
-                ],
-              },
-            ],
-          },
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  filter: [
-                    {
-                      bool: {
-                        should: [
-                          {
-                            match: {
-                              'global.name': 'GLOBAL',
-                            },
-                          },
-                        ],
-                        minimum_should_match: 1,
-                      },
-                    },
-                    {
-                      bool: {
-                        must_not: {
-                          bool: {
-                            should: [
-                              {
-                                match_phrase: {
-                                  'saved.obj.key1': 'key',
-                                },
-                              },
-                            ],
-                            minimum_should_match: 1,
-                          },
-                        },
-                      },
-                    },
-                  ],
-                },
-              },
-              {
-                bool: {
-                  should: [
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'pending',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'saved',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'global',
-                            },
-                          },
-                        ],
-                        must_not: [
-                          {
-                            exists: {
-                              field: 'namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-          },
-        },
+          search,
+          defaultSearchOperator: undefined,
+        });
+        expectResult(result, expect.not.objectContaining({ default_operator: expect.anything() }));
       });
-    });
-    it(' with search and searchFields', () => {
-      expect(
-        getQueryParams({
-          mappings: MAPPINGS,
+
+      it('includes specified default operator', () => {
+        const defaultSearchOperator = 'AND';
+        const result = getQueryParams({
+          mappings,
           registry,
-          namespace: 'foo-namespace',
-          search: 'y*',
-          searchFields: ['title'],
-          kueryNode: {
-            type: 'function',
-            function: 'is',
-            arguments: [
-              { type: 'literal', value: 'global.name' },
-              { type: 'literal', value: 'GLOBAL' },
-              { type: 'literal', value: false },
-            ],
-          },
-        })
-      ).toEqual({
-        query: {
-          bool: {
-            filter: [
-              {
-                bool: {
-                  should: [
-                    {
-                      match: {
-                        'global.name': 'GLOBAL',
-                      },
-                    },
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-              {
-                bool: {
-                  should: [
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'pending',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'saved',
-                            },
-                          },
-                          {
-                            term: {
-                              namespace: 'foo-namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                    {
-                      bool: {
-                        must: [
-                          {
-                            term: {
-                              type: 'global',
-                            },
-                          },
-                        ],
-                        must_not: [
-                          {
-                            exists: {
-                              field: 'namespace',
-                            },
-                          },
-                        ],
-                      },
-                    },
-                  ],
-                  minimum_should_match: 1,
-                },
-              },
-            ],
-            must: [
-              {
-                simple_query_string: {
-                  query: 'y*',
-                  fields: ['pending.title', 'saved.title', 'global.title'],
-                },
-              },
-            ],
-          },
-        },
+          search,
+          defaultSearchOperator,
+        });
+        expectResult(result, expect.objectContaining({ default_operator: defaultSearchOperator }));
       });
     });
   });
diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts
index e6c06208ca1a5..967ce8bceaf84 100644
--- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts
+++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts
@@ -66,18 +66,26 @@ function getClauseForType(
   namespace: string | undefined,
   type: string
 ) {
-  if (namespace && !registry.isNamespaceAgnostic(type)) {
+  if (registry.isMultiNamespace(type)) {
+    return {
+      bool: {
+        must: [{ term: { type } }, { term: { namespaces: namespace ?? 'default' } }],
+        must_not: [{ exists: { field: 'namespace' } }],
+      },
+    };
+  } else if (namespace && registry.isSingleNamespace(type)) {
     return {
       bool: {
         must: [{ term: { type } }, { term: { namespace } }],
+        must_not: [{ exists: { field: 'namespaces' } }],
       },
     };
   }
-
+  // isSingleNamespace in the default namespace, or isNamespaceAgnostic
   return {
     bool: {
       must: [{ term: { type } }],
-      must_not: [{ exists: { field: 'namespace' } }],
+      must_not: [{ exists: { field: 'namespace' } }, { exists: { field: 'namespaces' } }],
     },
   };
 }
diff --git a/src/core/server/saved_objects/service/saved_objects_client.mock.ts b/src/core/server/saved_objects/service/saved_objects_client.mock.ts
index c6de9fa94291c..b209c9ca54f63 100644
--- a/src/core/server/saved_objects/service/saved_objects_client.mock.ts
+++ b/src/core/server/saved_objects/service/saved_objects_client.mock.ts
@@ -31,6 +31,8 @@ const create = () =>
     find: jest.fn(),
     get: jest.fn(),
     update: jest.fn(),
+    addToNamespaces: jest.fn(),
+    deleteFromNamespaces: jest.fn(),
   } as unknown) as jest.Mocked<SavedObjectsClientContract>);
 
 export const savedObjectsClientMock = { create };
diff --git a/src/core/server/saved_objects/service/saved_objects_client.test.js b/src/core/server/saved_objects/service/saved_objects_client.test.js
index 1794d9ae86c17..53bb31369adbf 100644
--- a/src/core/server/saved_objects/service/saved_objects_client.test.js
+++ b/src/core/server/saved_objects/service/saved_objects_client.test.js
@@ -147,3 +147,37 @@ test(`#bulkUpdate`, async () => {
   });
   expect(result).toBe(returnValue);
 });
+
+test(`#addToNamespaces`, async () => {
+  const returnValue = Symbol();
+  const mockRepository = {
+    addToNamespaces: jest.fn().mockResolvedValue(returnValue),
+  };
+  const client = new SavedObjectsClient(mockRepository);
+
+  const type = Symbol();
+  const id = Symbol();
+  const namespaces = Symbol();
+  const options = Symbol();
+  const result = await client.addToNamespaces(type, id, namespaces, options);
+
+  expect(mockRepository.addToNamespaces).toHaveBeenCalledWith(type, id, namespaces, options);
+  expect(result).toBe(returnValue);
+});
+
+test(`#deleteFromNamespaces`, async () => {
+  const returnValue = Symbol();
+  const mockRepository = {
+    deleteFromNamespaces: jest.fn().mockResolvedValue(returnValue),
+  };
+  const client = new SavedObjectsClient(mockRepository);
+
+  const type = Symbol();
+  const id = Symbol();
+  const namespaces = Symbol();
+  const options = Symbol();
+  const result = await client.deleteFromNamespaces(type, id, namespaces, options);
+
+  expect(mockRepository.deleteFromNamespaces).toHaveBeenCalledWith(type, id, namespaces, options);
+  expect(result).toBe(returnValue);
+});
diff --git a/src/core/server/saved_objects/service/saved_objects_client.ts b/src/core/server/saved_objects/service/saved_objects_client.ts
index 70d69374ba8fe..8780f07cc3091 100644
--- a/src/core/server/saved_objects/service/saved_objects_client.ts
+++ b/src/core/server/saved_objects/service/saved_objects_client.ts
@@ -107,6 +107,26 @@ export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions {
   refresh?: MutatingOperationRefreshSetting;
 }
 
+/**
+ *
+ * @public
+ */
+export interface SavedObjectsAddToNamespacesOptions extends SavedObjectsBaseOptions {
+  /** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */
+  version?: string;
+  /** The Elasticsearch Refresh setting for this operation */
+  refresh?: MutatingOperationRefreshSetting;
+}
+
+/**
+ *
+ * @public
+ */
+export interface SavedObjectsDeleteFromNamespacesOptions extends SavedObjectsBaseOptions {
+  /** The Elasticsearch Refresh setting for this operation */
+  refresh?: MutatingOperationRefreshSetting;
+}
+
 /**
  *
  * @public
@@ -270,6 +290,40 @@ export class SavedObjectsClient {
     return await this._repository.update(type, id, attributes, options);
   }
 
+  /**
+   * Adds namespaces to a SavedObject
+   *
+   * @param type
+   * @param id
+   * @param namespaces
+   * @param options
+   */
+  async addToNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsAddToNamespacesOptions = {}
+  ): Promise<{}> {
+    return await this._repository.addToNamespaces(type, id, namespaces, options);
+  }
+
+  /**
+   * Removes namespaces from a SavedObject
+   *
+   * @param type
+   * @param id
+   * @param namespaces
+   * @param options
+   */
+  async deleteFromNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsDeleteFromNamespacesOptions = {}
+  ): Promise<{}> {
+    return await this._repository.deleteFromNamespaces(type, id, namespaces, options);
+  }
+
   /**
    * Bulk Updates multiple SavedObject at once
    *
diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts
index f14e9d9efb5e3..9efc82603b179 100644
--- a/src/core/server/saved_objects/types.ts
+++ b/src/core/server/saved_objects/types.ts
@@ -172,6 +172,19 @@ export type MutatingOperationRefreshSetting = boolean | 'wait_for';
  */
 export type SavedObjectsClientContract = Pick<SavedObjectsClient, keyof SavedObjectsClient>;
 
+/**
+ * The namespace type dictates how a saved object can be interacted in relation to namespaces. Each type is mutually exclusive:
+ *  * single (default): this type of saved object is namespace-isolated, e.g., it exists in only one namespace.
+ *  * multiple: this type of saved object is shareable, e.g., it can exist in one or more namespaces.
+ *  * agnostic: this type of saved object is global.
+ *
+ * Note: do not write logic that uses this value directly; instead, use the appropriate accessors in the
+ * {@link SavedObjectTypeRegistry | type registry}.
+ *
+ * @public
+ */
+export type SavedObjectsNamespaceType = 'single' | 'multiple' | 'agnostic';
+
 /**
  * @remarks This is only internal for now, and will only be public when we expose the registerType API
  *
@@ -190,9 +203,14 @@ export interface SavedObjectsType {
    */
   hidden: boolean;
   /**
-   * Is the type global (true), or namespaced (false).
+   * Is the type global (true), or not (false).
+   * @deprecated Use `namespaceType` instead.
+   */
+  namespaceAgnostic?: boolean;
+  /**
+   * The {@link SavedObjectsNamespaceType | namespace type} for the type.
    */
-  namespaceAgnostic: boolean;
+  namespaceType?: SavedObjectsNamespaceType;
   /**
    * If defined, the type instances will be stored in the given index instead of the default one.
    */
@@ -329,6 +347,8 @@ export type SavedObjectLegacyMigrationFn = (
  */
 interface SavedObjectsLegacyTypeSchema {
   isNamespaceAgnostic?: boolean;
+  /** Cannot be used in conjunction with `isNamespaceAgnostic` */
+  multiNamespace?: boolean;
   hidden?: boolean;
   indexPattern?: ((config: LegacyConfig) => string) | string;
   convertToAliasScript?: string;
diff --git a/src/core/server/saved_objects/utils.test.ts b/src/core/server/saved_objects/utils.test.ts
index 0719fe7138e8a..64bdf1771decc 100644
--- a/src/core/server/saved_objects/utils.test.ts
+++ b/src/core/server/saved_objects/utils.test.ts
@@ -84,6 +84,16 @@ describe('convertLegacyTypes', () => {
         },
         {
           pluginId: 'pluginB',
+          properties: {
+            typeB: {
+              properties: {
+                fieldB: { type: 'text' },
+              },
+            },
+          },
+        },
+        {
+          pluginId: 'pluginC',
           properties: {
             typeC: {
               properties: {
@@ -92,6 +102,16 @@ describe('convertLegacyTypes', () => {
             },
           },
         },
+        {
+          pluginId: 'pluginD',
+          properties: {
+            typeD: {
+              properties: {
+                fieldD: { type: 'text' },
+              },
+            },
+          },
+        },
       ],
       savedObjectMigrations: {},
       savedObjectSchemas: {
@@ -100,6 +120,18 @@ describe('convertLegacyTypes', () => {
           hidden: true,
           isNamespaceAgnostic: true,
         },
+        typeB: {
+          indexPattern: 'barBaz',
+          hidden: false,
+          multiNamespace: true,
+        },
+        typeD: {
+          indexPattern: 'bazQux',
+          hidden: false,
+          // if both isNamespaceAgnostic and multiNamespace are true, the resulting namespaceType is 'agnostic'
+          isNamespaceAgnostic: true,
+          multiNamespace: true,
+        },
       },
       savedObjectValidations: {},
       savedObjectsManagement: {},
@@ -372,29 +404,56 @@ describe('convertTypesToLegacySchema', () => {
       {
         name: 'typeA',
         hidden: false,
-        namespaceAgnostic: true,
+        namespaceType: 'agnostic',
         mappings: { properties: {} },
         convertToAliasScript: 'some script',
       },
       {
         name: 'typeB',
         hidden: true,
-        namespaceAgnostic: false,
+        namespaceType: 'single',
         indexPattern: 'myIndex',
         mappings: { properties: {} },
       },
+      {
+        name: 'typeC',
+        hidden: false,
+        namespaceType: 'multiple',
+        mappings: { properties: {} },
+      },
+      // deprecated test case
+      {
+        name: 'typeD',
+        hidden: false,
+        namespaceAgnostic: true,
+        namespaceType: 'multiple', // if namespaceAgnostic and namespaceType are both set, namespaceAgnostic takes precedence
+        mappings: { properties: {} },
+      },
     ];
     expect(convertTypesToLegacySchema(types)).toEqual({
       typeA: {
         hidden: false,
         isNamespaceAgnostic: true,
+        multiNamespace: false,
         convertToAliasScript: 'some script',
       },
       typeB: {
         hidden: true,
         isNamespaceAgnostic: false,
+        multiNamespace: false,
         indexPattern: 'myIndex',
       },
+      typeC: {
+        hidden: false,
+        isNamespaceAgnostic: false,
+        multiNamespace: true,
+      },
+      // deprecated test case
+      typeD: {
+        hidden: false,
+        isNamespaceAgnostic: true,
+        multiNamespace: false,
+      },
     });
   });
 });
diff --git a/src/core/server/saved_objects/utils.ts b/src/core/server/saved_objects/utils.ts
index ea90efd8b9fbd..5348963812629 100644
--- a/src/core/server/saved_objects/utils.ts
+++ b/src/core/server/saved_objects/utils.ts
@@ -20,6 +20,7 @@
 import { LegacyConfig } from '../legacy';
 import { SavedObjectMigrationMap } from './migrations';
 import {
+  SavedObjectsNamespaceType,
   SavedObjectsType,
   SavedObjectsLegacyUiExports,
   SavedObjectLegacyMigrationMap,
@@ -48,10 +49,15 @@ export const convertLegacyTypes = (
         const schema = savedObjectSchemas[type];
         const migrations = savedObjectMigrations[type];
         const management = savedObjectsManagement[type];
+        const namespaceType = (schema?.isNamespaceAgnostic
+          ? 'agnostic'
+          : schema?.multiNamespace
+          ? 'multiple'
+          : 'single') as SavedObjectsNamespaceType;
         return {
           name: type,
           hidden: schema?.hidden ?? false,
-          namespaceAgnostic: schema?.isNamespaceAgnostic ?? false,
+          namespaceType,
           mappings,
           indexPattern:
             typeof schema?.indexPattern === 'function'
@@ -76,7 +82,8 @@ export const convertTypesToLegacySchema = (
     return {
       ...schema,
       [type.name]: {
-        isNamespaceAgnostic: type.namespaceAgnostic,
+        isNamespaceAgnostic: type.namespaceAgnostic || type.namespaceType === 'agnostic',
+        multiNamespace: !type.namespaceAgnostic && type.namespaceType === 'multiple',
         hidden: type.hidden,
         indexPattern: type.indexPattern,
         convertToAliasScript: type.convertToAliasScript,
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index f3e3b7736d8d3..a35bca7375286 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -1003,7 +1003,7 @@ export type IsAuthenticated = (request: KibanaRequest | LegacyRequest) => boolea
 export type ISavedObjectsRepository = Pick<SavedObjectsRepository, keyof SavedObjectsRepository>;
 
 // @public
-export type ISavedObjectTypeRegistry = Pick<SavedObjectTypeRegistry, 'getType' | 'getAllTypes' | 'getIndex' | 'isNamespaceAgnostic' | 'isHidden' | 'getImportableAndExportableTypes' | 'isImportableAndExportable'>;
+export type ISavedObjectTypeRegistry = Omit<SavedObjectTypeRegistry, 'registerType'>;
 
 // @public
 export type IScopedClusterClient = Pick<ScopedClusterClient, 'callAsCurrentUser' | 'callAsInternalUser'>;
@@ -1643,6 +1643,7 @@ export interface SavedObject<T = unknown> {
     };
     id: string;
     migrationVersion?: SavedObjectsMigrationVersion;
+    namespaces?: string[];
     references: SavedObjectReference[];
     type: string;
     updated_at?: string;
@@ -1687,6 +1688,12 @@ export interface SavedObjectReference {
     type: string;
 }
 
+// @public (undocumented)
+export interface SavedObjectsAddToNamespacesOptions extends SavedObjectsBaseOptions {
+    refresh?: MutatingOperationRefreshSetting;
+    version?: string;
+}
+
 // Warning: (ae-forgotten-export) The symbol "SavedObjectDoc" needs to be exported by the entry point index.d.ts
 // Warning: (ae-forgotten-export) The symbol "Referencable" needs to be exported by the entry point index.d.ts
 //
@@ -1754,11 +1761,13 @@ export interface SavedObjectsBulkUpdateResponse<T = unknown> {
 export class SavedObjectsClient {
     // @internal
     constructor(repository: ISavedObjectsRepository);
+    addToNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsAddToNamespacesOptions): Promise<{}>;
     bulkCreate<T = unknown>(objects: Array<SavedObjectsBulkCreateObject<T>>, options?: SavedObjectsCreateOptions): Promise<SavedObjectsBulkResponse<T>>;
     bulkGet<T = unknown>(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise<SavedObjectsBulkResponse<T>>;
     bulkUpdate<T = unknown>(objects: Array<SavedObjectsBulkUpdateObject<T>>, options?: SavedObjectsBulkUpdateOptions): Promise<SavedObjectsBulkUpdateResponse<T>>;
     create<T = unknown>(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise<SavedObject<T>>;
     delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>;
+    deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<{}>;
     // (undocumented)
     static errors: typeof SavedObjectsErrorHelpers;
     // (undocumented)
@@ -1839,6 +1848,11 @@ export interface SavedObjectsDeleteByNamespaceOptions extends SavedObjectsBaseOp
     refresh?: MutatingOperationRefreshSetting;
 }
 
+// @public (undocumented)
+export interface SavedObjectsDeleteFromNamespacesOptions extends SavedObjectsBaseOptions {
+    refresh?: MutatingOperationRefreshSetting;
+}
+
 // @public (undocumented)
 export interface SavedObjectsDeleteOptions extends SavedObjectsBaseOptions {
     refresh?: MutatingOperationRefreshSetting;
@@ -1849,6 +1863,8 @@ export class SavedObjectsErrorHelpers {
     // (undocumented)
     static createBadRequestError(reason?: string): DecoratedError;
     // (undocumented)
+    static createConflictError(type: string, id: string): DecoratedError;
+    // (undocumented)
     static createEsAutoCreateIndexError(): DecoratedError;
     // (undocumented)
     static createGenericNotFoundError(type?: string | null, id?: string | null): DecoratedError;
@@ -1861,6 +1877,8 @@ export class SavedObjectsErrorHelpers {
     // (undocumented)
     static decorateConflictError(error: Error, reason?: string): DecoratedError;
     // (undocumented)
+    static decorateEsCannotExecuteScriptError(error: Error, reason?: string): DecoratedError;
+    // (undocumented)
     static decorateEsUnavailableError(error: Error, reason?: string): DecoratedError;
     // (undocumented)
     static decorateForbiddenError(error: Error, reason?: string): DecoratedError;
@@ -1877,6 +1895,8 @@ export class SavedObjectsErrorHelpers {
     // (undocumented)
     static isEsAutoCreateIndexError(error: Error | DecoratedError): boolean;
     // (undocumented)
+    static isEsCannotExecuteScriptError(error: Error | DecoratedError): boolean;
+    // (undocumented)
     static isEsUnavailableError(error: Error | DecoratedError): boolean;
     // (undocumented)
     static isForbiddenError(error: Error | DecoratedError): boolean;
@@ -2106,6 +2126,9 @@ export interface SavedObjectsMigrationVersion {
     [pluginName: string]: string;
 }
 
+// @public
+export type SavedObjectsNamespaceType = 'single' | 'multiple' | 'agnostic';
+
 // @public
 export interface SavedObjectsRawDoc {
     // (undocumented)
@@ -2124,6 +2147,7 @@ export interface SavedObjectsRawDoc {
 
 // @public (undocumented)
 export class SavedObjectsRepository {
+    addToNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsAddToNamespacesOptions): Promise<{}>;
     bulkCreate<T = unknown>(objects: Array<SavedObjectsBulkCreateObject<T>>, options?: SavedObjectsCreateOptions): Promise<SavedObjectsBulkResponse<T>>;
     bulkGet<T = unknown>(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise<SavedObjectsBulkResponse<T>>;
     bulkUpdate<T = unknown>(objects: Array<SavedObjectsBulkUpdateObject<T>>, options?: SavedObjectsBulkUpdateOptions): Promise<SavedObjectsBulkUpdateResponse<T>>;
@@ -2134,6 +2158,7 @@ export class SavedObjectsRepository {
     static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, callCluster: APICaller, extraTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository;
     delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>;
     deleteByNamespace(namespace: string, options?: SavedObjectsDeleteByNamespaceOptions): Promise<any>;
+    deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<{}>;
     // (undocumented)
     find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
     get<T = unknown>(type: string, id: string, options?: SavedObjectsBaseOptions): Promise<SavedObject<T>>;
@@ -2175,7 +2200,11 @@ export class SavedObjectsSchema {
     // (undocumented)
     isHiddenType(type: string): boolean;
     // (undocumented)
+    isMultiNamespace(type: string): boolean;
+    // (undocumented)
     isNamespaceAgnostic(type: string): boolean;
+    // (undocumented)
+    isSingleNamespace(type: string): boolean;
 }
 
 // @public
@@ -2224,7 +2253,9 @@ export interface SavedObjectsType {
     mappings: SavedObjectsTypeMappingDefinition;
     migrations?: SavedObjectMigrationMap;
     name: string;
-    namespaceAgnostic: boolean;
+    // @deprecated
+    namespaceAgnostic?: boolean;
+    namespaceType?: SavedObjectsNamespaceType;
 }
 
 // @public
@@ -2269,7 +2300,9 @@ export class SavedObjectTypeRegistry {
     getType(type: string): SavedObjectsType | undefined;
     isHidden(type: string): boolean;
     isImportableAndExportable(type: string): boolean;
+    isMultiNamespace(type: string): boolean;
     isNamespaceAgnostic(type: string): boolean;
+    isSingleNamespace(type: string): boolean;
     registerType(type: SavedObjectsType): void;
     }
 
diff --git a/src/core/types/saved_objects.ts b/src/core/types/saved_objects.ts
index d3faab6c557cd..04aaacc3cf31a 100644
--- a/src/core/types/saved_objects.ts
+++ b/src/core/types/saved_objects.ts
@@ -96,4 +96,6 @@ export interface SavedObject<T = unknown> {
   references: SavedObjectReference[];
   /** {@inheritdoc SavedObjectsMigrationVersion} */
   migrationVersion?: SavedObjectsMigrationVersion;
+  /** Namespace(s) that this saved object exists in. This attribute is only used for multi-namespace saved object types. */
+  namespaces?: string[];
 }
diff --git a/test/api_integration/apis/saved_objects/bulk_create.js b/test/api_integration/apis/saved_objects/bulk_create.js
index afa5153336ff7..2d77fdf266793 100644
--- a/test/api_integration/apis/saved_objects/bulk_create.js
+++ b/test/api_integration/apis/saved_objects/bulk_create.js
@@ -58,7 +58,9 @@ export default function({ getService }) {
                   type: 'visualization',
                   id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
                   error: {
-                    message: 'version conflict, document already exists',
+                    error: 'Conflict',
+                    message:
+                      'Saved object [visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab] conflict',
                     statusCode: 409,
                   },
                 },
diff --git a/test/api_integration/apis/saved_objects/bulk_get.js b/test/api_integration/apis/saved_objects/bulk_get.js
index 984ac781d3e46..67e511f2bf548 100644
--- a/test/api_integration/apis/saved_objects/bulk_get.js
+++ b/test/api_integration/apis/saved_objects/bulk_get.js
@@ -80,8 +80,9 @@ export default function({ getService }) {
                   id: 'does not exist',
                   type: 'dashboard',
                   error: {
+                    error: 'Not Found',
+                    message: 'Saved object [dashboard/does not exist] not found',
                     statusCode: 404,
-                    message: 'Not found',
                   },
                 },
                 {
@@ -123,24 +124,28 @@ export default function({ getService }) {
                   id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
                   type: 'visualization',
                   error: {
+                    error: 'Not Found',
+                    message:
+                      'Saved object [visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab] not found',
                     statusCode: 404,
-                    message: 'Not found',
                   },
                 },
                 {
                   id: 'does not exist',
                   type: 'dashboard',
                   error: {
+                    error: 'Not Found',
+                    message: 'Saved object [dashboard/does not exist] not found',
                     statusCode: 404,
-                    message: 'Not found',
                   },
                 },
                 {
                   id: '7.0.0-alpha1',
                   type: 'config',
                   error: {
+                    error: 'Not Found',
+                    message: 'Saved object [config/7.0.0-alpha1] not found',
                     statusCode: 404,
-                    message: 'Not found',
                   },
                 },
               ],
diff --git a/test/api_integration/apis/saved_objects/export.js b/test/api_integration/apis/saved_objects/export.js
index fc9ab8140869c..9558e82880deb 100644
--- a/test/api_integration/apis/saved_objects/export.js
+++ b/test/api_integration/apis/saved_objects/export.js
@@ -170,8 +170,9 @@ export default function({ getService }) {
                       id: '1',
                       type: 'dashboard',
                       error: {
+                        error: 'Not Found',
+                        message: 'Saved object [dashboard/1] not found',
                         statusCode: 404,
-                        message: 'Not found',
                       },
                     },
                   ],
diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts
index f691e62b9352a..2caf3a7055df9 100644
--- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts
+++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts
@@ -10,14 +10,16 @@ import { SavedObjectsClientContract } from 'src/core/server';
 import { EncryptedSavedObjectsService } from '../crypto';
 import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper';
 
-import { savedObjectsClientMock } from 'src/core/server/mocks';
+import { savedObjectsClientMock, savedObjectsTypeRegistryMock } from 'src/core/server/mocks';
 import { encryptedSavedObjectsServiceMock } from '../crypto/index.mock';
 
 let wrapper: EncryptedSavedObjectsClientWrapper;
 let mockBaseClient: jest.Mocked<SavedObjectsClientContract>;
+let mockBaseTypeRegistry: ReturnType<typeof savedObjectsTypeRegistryMock.create>;
 let encryptedSavedObjectsServiceMockInstance: jest.Mocked<EncryptedSavedObjectsService>;
 beforeEach(() => {
   mockBaseClient = savedObjectsClientMock.create();
+  mockBaseTypeRegistry = savedObjectsTypeRegistryMock.create();
   encryptedSavedObjectsServiceMockInstance = encryptedSavedObjectsServiceMock.create([
     {
       type: 'known-type',
@@ -28,6 +30,7 @@ beforeEach(() => {
   wrapper = new EncryptedSavedObjectsClientWrapper({
     service: encryptedSavedObjectsServiceMockInstance,
     baseClient: mockBaseClient,
+    baseTypeRegistry: mockBaseTypeRegistry,
   } as any);
 });
 
@@ -91,35 +94,50 @@ describe('#create', () => {
     );
   });
 
-  it('uses `namespace` to encrypt attributes if it is specified', async () => {
-    const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
-    const options = { overwrite: true, namespace: 'some-namespace' };
-    const mockedResponse = {
-      id: 'uuid-v4-id',
-      type: 'known-type',
-      attributes: { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
-      references: [],
-    };
+  describe('namespace', () => {
+    const doTest = async (namespace: string, expectNamespaceInDescriptor: boolean) => {
+      const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
+      const options = { overwrite: true, namespace };
+      const mockedResponse = {
+        id: 'uuid-v4-id',
+        type: 'known-type',
+        attributes: { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
+        references: [],
+      };
 
-    mockBaseClient.create.mockResolvedValue(mockedResponse);
+      mockBaseClient.create.mockResolvedValue(mockedResponse);
 
-    expect(await wrapper.create('known-type', attributes, options)).toEqual({
-      ...mockedResponse,
-      attributes: { attrOne: 'one', attrThree: 'three' },
-    });
+      expect(await wrapper.create('known-type', attributes, options)).toEqual({
+        ...mockedResponse,
+        attributes: { attrOne: 'one', attrThree: 'three' },
+      });
 
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
-      { type: 'known-type', id: 'uuid-v4-id', namespace: 'some-namespace' },
-      { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
-    );
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
+        {
+          type: 'known-type',
+          id: 'uuid-v4-id',
+          namespace: expectNamespaceInDescriptor ? namespace : undefined,
+        },
+        { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
+      );
 
-    expect(mockBaseClient.create).toHaveBeenCalledTimes(1);
-    expect(mockBaseClient.create).toHaveBeenCalledWith(
-      'known-type',
-      { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
-      { id: 'uuid-v4-id', overwrite: true, namespace: 'some-namespace' }
-    );
+      expect(mockBaseClient.create).toHaveBeenCalledTimes(1);
+      expect(mockBaseClient.create).toHaveBeenCalledWith(
+        'known-type',
+        { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
+        { id: 'uuid-v4-id', overwrite: true, namespace }
+      );
+    };
+
+    it('uses `namespace` to encrypt attributes if it is specified when type is single-namespace', async () => {
+      await doTest('some-namespace', true);
+    });
+
+    it('does not use `namespace` to encrypt attributes if it is specified when type is not single-namespace', async () => {
+      mockBaseTypeRegistry.isSingleNamespace.mockReturnValue(false);
+      await doTest('some-namespace', false);
+    });
   });
 
   it('fails if base client fails', async () => {
@@ -190,14 +208,13 @@ describe('#bulkCreate', () => {
 
   it('fails if ID is specified for registered type', async () => {
     const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
-    const options = { namespace: 'some-namespace' };
 
     const bulkCreateParams = [
       { id: 'some-id', type: 'known-type', attributes },
       { type: 'unknown-type', attributes },
     ];
 
-    await expect(wrapper.bulkCreate(bulkCreateParams, options)).rejects.toThrowError(
+    await expect(wrapper.bulkCreate(bulkCreateParams)).rejects.toThrowError(
       'Predefined IDs are not allowed for saved objects with encrypted attributes.'
     );
 
@@ -257,39 +274,57 @@ describe('#bulkCreate', () => {
     );
   });
 
-  it('uses `namespace` to encrypt attributes if it is specified', async () => {
-    const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
-    const options = { namespace: 'some-namespace' };
-    const mockedResponse = {
-      saved_objects: [{ id: 'uuid-v4-id', type: 'known-type', attributes, references: [] }],
-    };
+  describe('namespace', () => {
+    const doTest = async (namespace: string, expectNamespaceInDescriptor: boolean) => {
+      const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
+      const options = { namespace };
+      const mockedResponse = {
+        saved_objects: [{ id: 'uuid-v4-id', type: 'known-type', attributes, references: [] }],
+      };
+
+      mockBaseClient.bulkCreate.mockResolvedValue(mockedResponse);
+
+      const bulkCreateParams = [{ type: 'known-type', attributes }];
+      await expect(wrapper.bulkCreate(bulkCreateParams, options)).resolves.toEqual({
+        saved_objects: [
+          {
+            ...mockedResponse.saved_objects[0],
+            attributes: { attrOne: 'one', attrThree: 'three' },
+          },
+        ],
+      });
 
-    mockBaseClient.bulkCreate.mockResolvedValue(mockedResponse);
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
+        {
+          type: 'known-type',
+          id: 'uuid-v4-id',
+          namespace: expectNamespaceInDescriptor ? namespace : undefined,
+        },
+        { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
+      );
+
+      expect(mockBaseClient.bulkCreate).toHaveBeenCalledTimes(1);
+      expect(mockBaseClient.bulkCreate).toHaveBeenCalledWith(
+        [
+          {
+            ...bulkCreateParams[0],
+            id: 'uuid-v4-id',
+            attributes: { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
+          },
+        ],
+        options
+      );
+    };
 
-    const bulkCreateParams = [{ type: 'known-type', attributes }];
-    await expect(wrapper.bulkCreate(bulkCreateParams, options)).resolves.toEqual({
-      saved_objects: [
-        { ...mockedResponse.saved_objects[0], attributes: { attrOne: 'one', attrThree: 'three' } },
-      ],
+    it('uses `namespace` to encrypt attributes if it is specified when type is single-namespace', async () => {
+      await doTest('some-namespace', true);
     });
 
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
-      { type: 'known-type', id: 'uuid-v4-id', namespace: 'some-namespace' },
-      { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
-    );
-
-    expect(mockBaseClient.bulkCreate).toHaveBeenCalledTimes(1);
-    expect(mockBaseClient.bulkCreate).toHaveBeenCalledWith(
-      [
-        {
-          ...bulkCreateParams[0],
-          id: 'uuid-v4-id',
-          attributes: { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
-        },
-      ],
-      options
-    );
+    it('does not use `namespace` to encrypt attributes if it is specified when type is not single-namespace', async () => {
+      mockBaseTypeRegistry.isSingleNamespace.mockReturnValue(false);
+      await doTest('some-namespace', false);
+    });
   });
 
   it('fails if base client fails', async () => {
@@ -432,63 +467,79 @@ describe('#bulkUpdate', () => {
     );
   });
 
-  it('uses `namespace` to encrypt attributes if it is specified', async () => {
-    const docs = [
-      {
-        id: 'some-id',
-        type: 'known-type',
-        attributes: {
-          attrOne: 'one',
-          attrSecret: 'secret',
-          attrThree: 'three',
-        },
-        version: 'some-version',
-      },
-    ];
-
-    mockBaseClient.bulkUpdate.mockResolvedValue({
-      saved_objects: docs.map(doc => ({ ...doc, references: undefined })),
-    });
-
-    await expect(wrapper.bulkUpdate(docs, { namespace: 'some-namespace' })).resolves.toEqual({
-      saved_objects: [
+  describe('namespace', () => {
+    const doTest = async (namespace: string, expectNamespaceInDescriptor: boolean) => {
+      const docs = [
         {
           id: 'some-id',
           type: 'known-type',
           attributes: {
             attrOne: 'one',
+            attrSecret: 'secret',
             attrThree: 'three',
           },
           version: 'some-version',
-          references: undefined,
         },
-      ],
-    });
-
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
-      { type: 'known-type', id: 'some-id', namespace: 'some-namespace' },
-      { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
-    );
+      ];
+      const options = { namespace };
+
+      mockBaseClient.bulkUpdate.mockResolvedValue({
+        saved_objects: docs.map(doc => ({ ...doc, references: undefined })),
+      });
+
+      await expect(wrapper.bulkUpdate(docs, options)).resolves.toEqual({
+        saved_objects: [
+          {
+            id: 'some-id',
+            type: 'known-type',
+            attributes: {
+              attrOne: 'one',
+              attrThree: 'three',
+            },
+            version: 'some-version',
+            references: undefined,
+          },
+        ],
+      });
 
-    expect(mockBaseClient.bulkUpdate).toHaveBeenCalledTimes(1);
-    expect(mockBaseClient.bulkUpdate).toHaveBeenCalledWith(
-      [
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
         {
-          id: 'some-id',
           type: 'known-type',
-          attributes: {
-            attrOne: 'one',
-            attrSecret: '*secret*',
-            attrThree: 'three',
+          id: 'some-id',
+          namespace: expectNamespaceInDescriptor ? namespace : undefined,
+        },
+        { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
+      );
+
+      expect(mockBaseClient.bulkUpdate).toHaveBeenCalledTimes(1);
+      expect(mockBaseClient.bulkUpdate).toHaveBeenCalledWith(
+        [
+          {
+            id: 'some-id',
+            type: 'known-type',
+            attributes: {
+              attrOne: 'one',
+              attrSecret: '*secret*',
+              attrThree: 'three',
+            },
+            version: 'some-version',
+
+            references: undefined,
           },
-          version: 'some-version',
+        ],
+        options
+      );
+    };
 
-          references: undefined,
-        },
-      ],
-      { namespace: 'some-namespace' }
-    );
+    it('uses `namespace` to encrypt attributes if it is specified when type is single-namespace', async () => {
+      await doTest('some-namespace', true);
+    });
+
+    it('does not use `namespace` to encrypt attributes if it is specified when type is not single-namespace', async () => {
+      mockBaseTypeRegistry.isSingleNamespace.mockReturnValue(false);
+      await doTest('some-namespace', false);
+    });
   });
 
   it('fails if base client fails', async () => {
@@ -871,31 +922,46 @@ describe('#update', () => {
     );
   });
 
-  it('uses `namespace` to encrypt attributes if it is specified', async () => {
-    const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
-    const options = { version: 'some-version', namespace: 'some-namespace' };
-    const mockedResponse = { id: 'some-id', type: 'known-type', attributes, references: [] };
+  describe('namespace', () => {
+    const doTest = async (namespace: string, expectNamespaceInDescriptor: boolean) => {
+      const attributes = { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' };
+      const options = { version: 'some-version', namespace };
+      const mockedResponse = { id: 'some-id', type: 'known-type', attributes, references: [] };
 
-    mockBaseClient.update.mockResolvedValue(mockedResponse);
+      mockBaseClient.update.mockResolvedValue(mockedResponse);
 
-    await expect(wrapper.update('known-type', 'some-id', attributes, options)).resolves.toEqual({
-      ...mockedResponse,
-      attributes: { attrOne: 'one', attrThree: 'three' },
-    });
+      await expect(wrapper.update('known-type', 'some-id', attributes, options)).resolves.toEqual({
+        ...mockedResponse,
+        attributes: { attrOne: 'one', attrThree: 'three' },
+      });
 
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
-    expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
-      { type: 'known-type', id: 'some-id', namespace: 'some-namespace' },
-      { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
-    );
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1);
+      expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith(
+        {
+          type: 'known-type',
+          id: 'some-id',
+          namespace: expectNamespaceInDescriptor ? namespace : undefined,
+        },
+        { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' }
+      );
+
+      expect(mockBaseClient.update).toHaveBeenCalledTimes(1);
+      expect(mockBaseClient.update).toHaveBeenCalledWith(
+        'known-type',
+        'some-id',
+        { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
+        options
+      );
+    };
 
-    expect(mockBaseClient.update).toHaveBeenCalledTimes(1);
-    expect(mockBaseClient.update).toHaveBeenCalledWith(
-      'known-type',
-      'some-id',
-      { attrOne: 'one', attrSecret: '*secret*', attrThree: 'three' },
-      options
-    );
+    it('uses `namespace` to encrypt attributes if it is specified when type is single-namespace', async () => {
+      await doTest('some-namespace', true);
+    });
+
+    it('does not use `namespace` to encrypt attributes if it is specified when type is not single-namespace', async () => {
+      mockBaseTypeRegistry.isSingleNamespace.mockReturnValue(false);
+      await doTest('some-namespace', false);
+    });
   });
 
   it('fails if base client fails', async () => {
diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts
index b4f1de52c9ce3..e8197536d29d9 100644
--- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts
+++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts
@@ -19,11 +19,15 @@ import {
   SavedObjectsFindResponse,
   SavedObjectsUpdateOptions,
   SavedObjectsUpdateResponse,
+  SavedObjectsAddToNamespacesOptions,
+  SavedObjectsDeleteFromNamespacesOptions,
+  ISavedObjectTypeRegistry,
 } from 'src/core/server';
 import { EncryptedSavedObjectsService } from '../crypto';
 
 interface EncryptedSavedObjectsClientOptions {
   baseClient: SavedObjectsClientContract;
+  baseTypeRegistry: ISavedObjectTypeRegistry;
   service: Readonly<EncryptedSavedObjectsService>;
 }
 
@@ -41,6 +45,10 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon
     public readonly errors = options.baseClient.errors
   ) {}
 
+  // only include namespace in AAD descriptor if the specified type is single-namespace
+  private getDescriptorNamespace = (type: string, namespace?: string) =>
+    this.options.baseTypeRegistry.isSingleNamespace(type) ? namespace : undefined;
+
   public async create<T = unknown>(
     type: string,
     attributes: T = {} as T,
@@ -60,11 +68,12 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon
     }
 
     const id = generateID();
+    const namespace = this.getDescriptorNamespace(type, options.namespace);
     return this.stripEncryptedAttributesFromResponse(
       await this.options.baseClient.create(
         type,
         await this.options.service.encryptAttributes(
-          { type, id, namespace: options.namespace },
+          { type, id, namespace },
           attributes as Record<string, unknown>
         ),
         { ...options, id }
@@ -95,11 +104,12 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon
         }
 
         const id = generateID();
+        const namespace = this.getDescriptorNamespace(object.type, options?.namespace);
         return {
           ...object,
           id,
           attributes: await this.options.service.encryptAttributes(
-            { type: object.type, id, namespace: options && options.namespace },
+            { type: object.type, id, namespace },
             object.attributes as Record<string, unknown>
           ),
         } as SavedObjectsBulkCreateObject<T>;
@@ -124,10 +134,11 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon
         if (!this.options.service.isRegistered(type)) {
           return object;
         }
+        const namespace = this.getDescriptorNamespace(type, options?.namespace);
         return {
           ...object,
           attributes: await this.options.service.encryptAttributes(
-            { type, id, namespace: options && options.namespace },
+            { type, id, namespace },
             attributes
           ),
         };
@@ -173,20 +184,35 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon
     if (!this.options.service.isRegistered(type)) {
       return await this.options.baseClient.update(type, id, attributes, options);
     }
-
+    const namespace = this.getDescriptorNamespace(type, options?.namespace);
     return this.stripEncryptedAttributesFromResponse(
       await this.options.baseClient.update(
         type,
         id,
-        await this.options.service.encryptAttributes(
-          { type, id, namespace: options && options.namespace },
-          attributes
-        ),
+        await this.options.service.encryptAttributes({ type, id, namespace }, attributes),
         options
       )
     );
   }
 
+  public async addToNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options?: SavedObjectsAddToNamespacesOptions
+  ) {
+    return await this.options.baseClient.addToNamespaces(type, id, namespaces, options);
+  }
+
+  public async deleteFromNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options?: SavedObjectsDeleteFromNamespacesOptions
+  ) {
+    return await this.options.baseClient.deleteFromNamespaces(type, id, namespaces, options);
+  }
+
   /**
    * Strips encrypted attributes from any non-bulk Saved Objects API response. If type isn't
    * registered, response is returned as is.
diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts
index c76477cd8da43..10599ae3a1798 100644
--- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts
+++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts
@@ -40,7 +40,8 @@ export function setupSavedObjects({
   savedObjects.addClientWrapper(
     Number.MAX_SAFE_INTEGER,
     'encryptedSavedObjects',
-    ({ client: baseClient }) => new EncryptedSavedObjectsClientWrapper({ baseClient, service })
+    ({ client: baseClient, typeRegistry: baseTypeRegistry }) =>
+      new EncryptedSavedObjectsClientWrapper({ baseClient, baseTypeRegistry, service })
   );
 
   const internalRepositoryPromise = getStartServices().then(([core]) =>
diff --git a/x-pack/plugins/security/server/audit/audit_logger.test.ts b/x-pack/plugins/security/server/audit/audit_logger.test.ts
index 01cde02b7dfdd..f7ee210a21a74 100644
--- a/x-pack/plugins/security/server/audit/audit_logger.test.ts
+++ b/x-pack/plugins/security/server/audit/audit_logger.test.ts
@@ -18,25 +18,46 @@ describe(`#savedObjectsAuthorizationFailure`, () => {
     const username = 'foo-user';
     const action = 'foo-action';
     const types = ['foo-type-1', 'foo-type-2'];
-    const missing = [`saved_object:${types[0]}/foo-action`, `saved_object:${types[1]}/foo-action`];
+    const spaceIds = ['foo-space', 'bar-space'];
+    const missing = [
+      {
+        spaceId: 'foo-space',
+        privilege: `saved_object:${types[0]}/${action}`,
+      },
+      {
+        spaceId: 'foo-space',
+        privilege: `saved_object:${types[1]}/${action}`,
+      },
+    ];
     const args = {
       foo: 'bar',
       baz: 'quz',
     };
 
-    securityAuditLogger.savedObjectsAuthorizationFailure(username, action, types, missing, args);
+    securityAuditLogger.savedObjectsAuthorizationFailure(
+      username,
+      action,
+      types,
+      spaceIds,
+      missing,
+      args
+    );
 
     expect(auditLogger.log).toHaveBeenCalledWith(
       'saved_objects_authorization_failure',
-      expect.stringContaining(`${username} unauthorized to ${action}`),
+      expect.any(String),
       {
         username,
         action,
         types,
+        spaceIds,
         missing,
         args,
       }
     );
+    expect(auditLogger.log.mock.calls[0][1]).toMatchInlineSnapshot(
+      `"foo-user unauthorized to [foo-action] [foo-type-1,foo-type-2] in [foo-space,bar-space]: missing [(foo-space)saved_object:foo-type-1/foo-action,(foo-space)saved_object:foo-type-2/foo-action]"`
+    );
   });
 });
 
@@ -47,22 +68,27 @@ describe(`#savedObjectsAuthorizationSuccess`, () => {
     const username = 'foo-user';
     const action = 'foo-action';
     const types = ['foo-type-1', 'foo-type-2'];
+    const spaceIds = ['foo-space', 'bar-space'];
     const args = {
       foo: 'bar',
       baz: 'quz',
     };
 
-    securityAuditLogger.savedObjectsAuthorizationSuccess(username, action, types, args);
+    securityAuditLogger.savedObjectsAuthorizationSuccess(username, action, types, spaceIds, args);
 
     expect(auditLogger.log).toHaveBeenCalledWith(
       'saved_objects_authorization_success',
-      expect.stringContaining(`${username} authorized to ${action}`),
+      expect.any(String),
       {
         username,
         action,
         types,
+        spaceIds,
         args,
       }
     );
+    expect(auditLogger.log.mock.calls[0][1]).toMatchInlineSnapshot(
+      `"foo-user authorized to [foo-action] [foo-type-1,foo-type-2] in [foo-space,bar-space]"`
+    );
   });
 });
diff --git a/x-pack/plugins/security/server/audit/audit_logger.ts b/x-pack/plugins/security/server/audit/audit_logger.ts
index df8df35f97b49..40b525b5d2188 100644
--- a/x-pack/plugins/security/server/audit/audit_logger.ts
+++ b/x-pack/plugins/security/server/audit/audit_logger.ts
@@ -13,16 +13,23 @@ export class SecurityAuditLogger {
     username: string,
     action: string,
     types: string[],
-    missing: string[],
+    spaceIds: string[],
+    missing: Array<{ spaceId?: string; privilege: string }>,
     args?: Record<string, unknown>
   ) {
+    const typesString = types.join(',');
+    const spacesString = spaceIds.length ? ` in [${spaceIds.join(',')}]` : '';
+    const missingString = missing
+      .map(({ spaceId, privilege }) => `${spaceId ? `(${spaceId})` : ''}${privilege}`)
+      .join(',');
     this.getAuditLogger().log(
       'saved_objects_authorization_failure',
-      `${username} unauthorized to ${action} ${types.join(',')}, missing ${missing.join(',')}`,
+      `${username} unauthorized to [${action}] [${typesString}]${spacesString}: missing [${missingString}]`,
       {
         username,
         action,
         types,
+        spaceIds,
         missing,
         args,
       }
@@ -33,15 +40,19 @@ export class SecurityAuditLogger {
     username: string,
     action: string,
     types: string[],
+    spaceIds: string[],
     args?: Record<string, unknown>
   ) {
+    const typesString = types.join(',');
+    const spacesString = spaceIds.length ? ` in [${spaceIds.join(',')}]` : '';
     this.getAuditLogger().log(
       'saved_objects_authorization_success',
-      `${username} authorized to ${action} ${types.join(',')}`,
+      `${username} authorized to [${action}] [${typesString}]${spacesString}`,
       {
         username,
         action,
         types,
+        spaceIds,
         args,
       }
     );
diff --git a/x-pack/plugins/security/server/authorization/__snapshots__/check_privileges.test.ts.snap b/x-pack/plugins/security/server/authorization/__snapshots__/check_privileges.test.ts.snap
deleted file mode 100644
index 1212c2cd6a5cb..0000000000000
--- a/x-pack/plugins/security/server/authorization/__snapshots__/check_privileges.test.ts.snap
+++ /dev/null
@@ -1,27 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`#atSpace throws error when checking for login and user has login but doesn't have version 1`] = `[Error: Multiple versions of Kibana are running against the same Elasticsearch cluster, unable to authorize user.]`;
-
-exports[`#atSpace with a malformed Elasticsearch response throws a validation error when an extra privilege is present in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because ["saved_object:bar-type/get" is not allowed]]]]`;
-
-exports[`#atSpace with a malformed Elasticsearch response throws a validation error when privileges are missing in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because [child "saved_object:foo-type/get" fails because ["saved_object:foo-type/get" is required]]]]]`;
-
-exports[`#atSpaces throws error when Elasticsearch returns malformed response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because [child "mock-action:version" fails because ["mock-action:version" is required]]]]]`;
-
-exports[`#atSpaces throws error when checking for login and user has login but doesn't have version 1`] = `[Error: Multiple versions of Kibana are running against the same Elasticsearch cluster, unable to authorize user.]`;
-
-exports[`#atSpaces with a malformed Elasticsearch response throws a validation error when an a space is missing in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`;
-
-exports[`#atSpaces with a malformed Elasticsearch response throws a validation error when an extra privilege is present in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`;
-
-exports[`#atSpaces with a malformed Elasticsearch response throws a validation error when an extra space is present in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because ["space:space_3" is not allowed]]]`;
-
-exports[`#atSpaces with a malformed Elasticsearch response throws a validation error when privileges are missing in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`;
-
-exports[`#globally throws error when Elasticsearch returns malformed response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because [child "mock-action:version" fails because ["mock-action:version" is required]]]]]`;
-
-exports[`#globally throws error when checking for login and user has login but doesn't have version 1`] = `[Error: Multiple versions of Kibana are running against the same Elasticsearch cluster, unable to authorize user.]`;
-
-exports[`#globally with a malformed Elasticsearch response throws a validation error when an extra privilege is present in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because ["saved_object:bar-type/get" is not allowed]]]]`;
-
-exports[`#globally with a malformed Elasticsearch response throws a validation error when privileges are missing in the response 1`] = `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because [child "saved_object:foo-type/get" fails because ["saved_object:foo-type/get" is required]]]]]`;
diff --git a/x-pack/plugins/security/server/authorization/check_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_privileges.test.ts
index 8c1241937892e..a64c5d509ca11 100644
--- a/x-pack/plugins/security/server/authorization/check_privileges.test.ts
+++ b/x-pack/plugins/security/server/authorization/check_privileges.test.ts
@@ -31,123 +31,121 @@ const createMockClusterClient = (response: any) => {
 };
 
 describe('#atSpace', () => {
-  const checkPrivilegesAtSpaceTest = (
-    description: string,
-    options: {
-      spaceId: string;
-      privilegeOrPrivileges: string | string[];
-      esHasPrivilegesResponse: HasPrivilegesResponse;
-      expectedResult?: any;
-      expectErrorThrown?: any;
+  const checkPrivilegesAtSpaceTest = async (options: {
+    spaceId: string;
+    privilegeOrPrivileges: string | string[];
+    esHasPrivilegesResponse: HasPrivilegesResponse;
+  }) => {
+    const { mockClusterClient, mockScopedClusterClient } = createMockClusterClient(
+      options.esHasPrivilegesResponse
+    );
+    const checkPrivilegesWithRequest = checkPrivilegesWithRequestFactory(
+      mockActions,
+      mockClusterClient,
+      application
+    );
+    const request = httpServerMock.createKibanaRequest();
+    const checkPrivileges = checkPrivilegesWithRequest(request);
+
+    let actualResult;
+    let errorThrown = null;
+    try {
+      actualResult = await checkPrivileges.atSpace(options.spaceId, options.privilegeOrPrivileges);
+    } catch (err) {
+      errorThrown = err;
     }
-  ) => {
-    test(description, async () => {
-      const { mockClusterClient, mockScopedClusterClient } = createMockClusterClient(
-        options.esHasPrivilegesResponse
-      );
-      const checkPrivilegesWithRequest = checkPrivilegesWithRequestFactory(
-        mockActions,
-        mockClusterClient,
-        application
-      );
-      const request = httpServerMock.createKibanaRequest();
-      const checkPrivileges = checkPrivilegesWithRequest(request);
-
-      let actualResult;
-      let errorThrown = null;
-      try {
-        actualResult = await checkPrivileges.atSpace(
-          options.spaceId,
-          options.privilegeOrPrivileges
-        );
-      } catch (err) {
-        errorThrown = err;
-      }
 
-      expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request);
-      expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith(
-        'shield.hasPrivileges',
-        {
-          body: {
-            applications: [
-              {
-                application,
-                resources: [`space:${options.spaceId}`],
-                privileges: uniq([
-                  mockActions.version,
-                  mockActions.login,
-                  ...(Array.isArray(options.privilegeOrPrivileges)
-                    ? options.privilegeOrPrivileges
-                    : [options.privilegeOrPrivileges]),
-                ]),
-              },
-            ],
+    expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request);
+    expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith('shield.hasPrivileges', {
+      body: {
+        applications: [
+          {
+            application,
+            resources: [`space:${options.spaceId}`],
+            privileges: uniq([
+              mockActions.version,
+              mockActions.login,
+              ...(Array.isArray(options.privilegeOrPrivileges)
+                ? options.privilegeOrPrivileges
+                : [options.privilegeOrPrivileges]),
+            ]),
           },
-        }
-      );
-
-      if (options.expectedResult) {
-        expect(errorThrown).toBeNull();
-        expect(actualResult).toEqual(options.expectedResult);
-      }
-
-      if (options.expectErrorThrown) {
-        expect(errorThrown).toMatchSnapshot();
-      }
+        ],
+      },
     });
+
+    if (errorThrown) {
+      return errorThrown;
+    }
+    return actualResult;
   };
 
-  checkPrivilegesAtSpaceTest('successful when checking for login and user has login', {
-    spaceId: 'space_1',
-    privilegeOrPrivileges: mockActions.login,
-    esHasPrivilegesResponse: {
-      has_all_requested: true,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          'space:space_1': {
-            [mockActions.login]: true,
-            [mockActions.version]: true,
+  test('successful when checking for login and user has login', async () => {
+    const result = await checkPrivilegesAtSpaceTest({
+      spaceId: 'space_1',
+      privilegeOrPrivileges: mockActions.login,
+      esHasPrivilegesResponse: {
+        has_all_requested: true,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            'space:space_1': {
+              [mockActions.login]: true,
+              [mockActions.version]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: true,
-      username: 'foo-username',
-      privileges: {
-        [mockActions.login]: true,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": true,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "mock-action:login",
+            "resource": "space_1",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
-  checkPrivilegesAtSpaceTest(`failure when checking for login and user doesn't have login`, {
-    spaceId: 'space_1',
-    privilegeOrPrivileges: mockActions.login,
-    esHasPrivilegesResponse: {
-      has_all_requested: false,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          'space:space_1': {
-            [mockActions.login]: false,
-            [mockActions.version]: true,
+  test(`failure when checking for login and user doesn't have login`, async () => {
+    const result = await checkPrivilegesAtSpaceTest({
+      spaceId: 'space_1',
+      privilegeOrPrivileges: mockActions.login,
+      esHasPrivilegesResponse: {
+        has_all_requested: false,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            'space:space_1': {
+              [mockActions.login]: false,
+              [mockActions.version]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: false,
-      username: 'foo-username',
-      privileges: {
-        [mockActions.login]: false,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": false,
+            "privilege": "mock-action:login",
+            "resource": "space_1",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
-  checkPrivilegesAtSpaceTest(
-    `throws error when checking for login and user has login but doesn't have version`,
-    {
+  test(`throws error when checking for login and user has login but doesn't have version`, async () => {
+    const result = await checkPrivilegesAtSpaceTest({
       spaceId: 'space_1',
       privilegeOrPrivileges: mockActions.login,
       esHasPrivilegesResponse: {
@@ -162,74 +160,99 @@ describe('#atSpace', () => {
           },
         },
       },
-      expectErrorThrown: true,
-    }
-  );
-
-  checkPrivilegesAtSpaceTest(`successful when checking for two actions and the user has both`, {
-    spaceId: 'space_1',
-    privilegeOrPrivileges: [
-      `saved_object:${savedObjectTypes[0]}/get`,
-      `saved_object:${savedObjectTypes[1]}/get`,
-    ],
-    esHasPrivilegesResponse: {
-      has_all_requested: true,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          'space:space_1': {
-            [mockActions.login]: true,
-            [mockActions.version]: true,
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+    });
+    expect(result).toMatchInlineSnapshot(
+      `[Error: Multiple versions of Kibana are running against the same Elasticsearch cluster, unable to authorize user.]`
+    );
+  });
+
+  test(`successful when checking for two actions and the user has both`, async () => {
+    const result = await checkPrivilegesAtSpaceTest({
+      spaceId: 'space_1',
+      privilegeOrPrivileges: [
+        `saved_object:${savedObjectTypes[0]}/get`,
+        `saved_object:${savedObjectTypes[1]}/get`,
+      ],
+      esHasPrivilegesResponse: {
+        has_all_requested: true,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            'space:space_1': {
+              [mockActions.login]: true,
+              [mockActions.version]: true,
+              [`saved_object:${savedObjectTypes[0]}/get`]: true,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: true,
-      username: 'foo-username',
-      privileges: {
-        [`saved_object:${savedObjectTypes[0]}/get`]: true,
-        [`saved_object:${savedObjectTypes[1]}/get`]: true,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": true,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_1",
+          },
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_1",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
-  checkPrivilegesAtSpaceTest(`failure when checking for two actions and the user has only one`, {
-    spaceId: 'space_1',
-    privilegeOrPrivileges: [
-      `saved_object:${savedObjectTypes[0]}/get`,
-      `saved_object:${savedObjectTypes[1]}/get`,
-    ],
-    esHasPrivilegesResponse: {
-      has_all_requested: false,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          'space:space_1': {
-            [mockActions.login]: true,
-            [mockActions.version]: true,
-            [`saved_object:${savedObjectTypes[0]}/get`]: false,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+  test(`failure when checking for two actions and the user has only one`, async () => {
+    const result = await checkPrivilegesAtSpaceTest({
+      spaceId: 'space_1',
+      privilegeOrPrivileges: [
+        `saved_object:${savedObjectTypes[0]}/get`,
+        `saved_object:${savedObjectTypes[1]}/get`,
+      ],
+      esHasPrivilegesResponse: {
+        has_all_requested: false,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            'space:space_1': {
+              [mockActions.login]: true,
+              [mockActions.version]: true,
+              [`saved_object:${savedObjectTypes[0]}/get`]: false,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: false,
-      username: 'foo-username',
-      privileges: {
-        [`saved_object:${savedObjectTypes[0]}/get`]: false,
-        [`saved_object:${savedObjectTypes[1]}/get`]: true,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_1",
+          },
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_1",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
   describe('with a malformed Elasticsearch response', () => {
-    checkPrivilegesAtSpaceTest(
-      `throws a validation error when an extra privilege is present in the response`,
-      {
+    test(`throws a validation error when an extra privilege is present in the response`, async () => {
+      const result = await checkPrivilegesAtSpaceTest({
         spaceId: 'space_1',
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
@@ -246,13 +269,14 @@ describe('#atSpace', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because ["saved_object:bar-type/get" is not allowed]]]]`
+      );
+    });
 
-    checkPrivilegesAtSpaceTest(
-      `throws a validation error when privileges are missing in the response`,
-      {
+    test(`throws a validation error when privileges are missing in the response`, async () => {
+      const result = await checkPrivilegesAtSpaceTest({
         spaceId: 'space_1',
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
@@ -267,82 +291,69 @@ describe('#atSpace', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because [child "saved_object:foo-type/get" fails because ["saved_object:foo-type/get" is required]]]]]`
+      );
+    });
   });
 });
 
 describe('#atSpaces', () => {
-  const checkPrivilegesAtSpacesTest = (
-    description: string,
-    options: {
-      spaceIds: string[];
-      privilegeOrPrivileges: string | string[];
-      esHasPrivilegesResponse: HasPrivilegesResponse;
-      expectedResult?: any;
-      expectErrorThrown?: any;
-    }
-  ) => {
-    test(description, async () => {
-      const { mockClusterClient, mockScopedClusterClient } = createMockClusterClient(
-        options.esHasPrivilegesResponse
-      );
-      const checkPrivilegesWithRequest = checkPrivilegesWithRequestFactory(
-        mockActions,
-        mockClusterClient,
-        application
-      );
-      const request = httpServerMock.createKibanaRequest();
-      const checkPrivileges = checkPrivilegesWithRequest(request);
-
-      let actualResult;
-      let errorThrown = null;
-      try {
-        actualResult = await checkPrivileges.atSpaces(
-          options.spaceIds,
-          options.privilegeOrPrivileges
-        );
-      } catch (err) {
-        errorThrown = err;
-      }
+  const checkPrivilegesAtSpacesTest = async (options: {
+    spaceIds: string[];
+    privilegeOrPrivileges: string | string[];
+    esHasPrivilegesResponse: HasPrivilegesResponse;
+  }) => {
+    const { mockClusterClient, mockScopedClusterClient } = createMockClusterClient(
+      options.esHasPrivilegesResponse
+    );
+    const checkPrivilegesWithRequest = checkPrivilegesWithRequestFactory(
+      mockActions,
+      mockClusterClient,
+      application
+    );
+    const request = httpServerMock.createKibanaRequest();
+    const checkPrivileges = checkPrivilegesWithRequest(request);
 
-      expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request);
-      expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith(
-        'shield.hasPrivileges',
-        {
-          body: {
-            applications: [
-              {
-                application,
-                resources: options.spaceIds.map(spaceId => `space:${spaceId}`),
-                privileges: uniq([
-                  mockActions.version,
-                  mockActions.login,
-                  ...(Array.isArray(options.privilegeOrPrivileges)
-                    ? options.privilegeOrPrivileges
-                    : [options.privilegeOrPrivileges]),
-                ]),
-              },
-            ],
-          },
-        }
+    let actualResult;
+    let errorThrown = null;
+    try {
+      actualResult = await checkPrivileges.atSpaces(
+        options.spaceIds,
+        options.privilegeOrPrivileges
       );
+    } catch (err) {
+      errorThrown = err;
+    }
 
-      if (options.expectedResult) {
-        expect(errorThrown).toBeNull();
-        expect(actualResult).toEqual(options.expectedResult);
-      }
-
-      if (options.expectErrorThrown) {
-        expect(errorThrown).toMatchSnapshot();
-      }
+    expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request);
+    expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith('shield.hasPrivileges', {
+      body: {
+        applications: [
+          {
+            application,
+            resources: options.spaceIds.map(spaceId => `space:${spaceId}`),
+            privileges: uniq([
+              mockActions.version,
+              mockActions.login,
+              ...(Array.isArray(options.privilegeOrPrivileges)
+                ? options.privilegeOrPrivileges
+                : [options.privilegeOrPrivileges]),
+            ]),
+          },
+        ],
+      },
     });
+
+    if (errorThrown) {
+      return errorThrown;
+    }
+    return actualResult;
   };
 
-  checkPrivilegesAtSpacesTest(
-    'successful when checking for login and user has login at both spaces',
-    {
+  test('successful when checking for login and user has login at both spaces', async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: mockActions.login,
       esHasPrivilegesResponse: {
@@ -361,24 +372,29 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectedResult: {
-        hasAllRequested: true,
-        username: 'foo-username',
-        spacePrivileges: {
-          space_1: {
-            [mockActions.login]: true,
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": true,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "mock-action:login",
+            "resource": "space_1",
           },
-          space_2: {
-            [mockActions.login]: true,
+          Object {
+            "authorized": true,
+            "privilege": "mock-action:login",
+            "resource": "space_2",
           },
-        },
-      },
-    }
-  );
+        ],
+        "username": "foo-username",
+      }
+    `);
+  });
 
-  checkPrivilegesAtSpacesTest(
-    'failure when checking for login and user has login at only one space',
-    {
+  test('failure when checking for login and user has login at only one space', async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: mockActions.login,
       esHasPrivilegesResponse: {
@@ -397,24 +413,29 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectedResult: {
-        hasAllRequested: false,
-        username: 'foo-username',
-        spacePrivileges: {
-          space_1: {
-            [mockActions.login]: true,
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "mock-action:login",
+            "resource": "space_1",
           },
-          space_2: {
-            [mockActions.login]: false,
+          Object {
+            "authorized": false,
+            "privilege": "mock-action:login",
+            "resource": "space_2",
           },
-        },
-      },
-    }
-  );
+        ],
+        "username": "foo-username",
+      }
+    `);
+  });
 
-  checkPrivilegesAtSpacesTest(
-    `throws error when checking for login and user has login but doesn't have version`,
-    {
+  test(`throws error when checking for login and user has login but doesn't have version`, async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: mockActions.login,
       esHasPrivilegesResponse: {
@@ -433,38 +454,43 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectErrorThrown: true,
-    }
-  );
-
-  checkPrivilegesAtSpacesTest(`throws error when Elasticsearch returns malformed response`, {
-    spaceIds: ['space_1', 'space_2'],
-    privilegeOrPrivileges: [
-      `saved_object:${savedObjectTypes[0]}/get`,
-      `saved_object:${savedObjectTypes[1]}/get`,
-    ],
-    esHasPrivilegesResponse: {
-      has_all_requested: true,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          'space:space_1': {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
-          },
-          'space:space_2': {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+    });
+    expect(result).toMatchInlineSnapshot(
+      `[Error: Multiple versions of Kibana are running against the same Elasticsearch cluster, unable to authorize user.]`
+    );
+  });
+
+  test(`throws error when Elasticsearch returns malformed response`, async () => {
+    const result = await checkPrivilegesAtSpacesTest({
+      spaceIds: ['space_1', 'space_2'],
+      privilegeOrPrivileges: [
+        `saved_object:${savedObjectTypes[0]}/get`,
+        `saved_object:${savedObjectTypes[1]}/get`,
+      ],
+      esHasPrivilegesResponse: {
+        has_all_requested: true,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            'space:space_1': {
+              [`saved_object:${savedObjectTypes[0]}/get`]: true,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
+            'space:space_2': {
+              [`saved_object:${savedObjectTypes[0]}/get`]: true,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
           },
         },
       },
-    },
-    expectErrorThrown: true,
+    });
+    expect(result).toMatchInlineSnapshot(
+      `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because [child "mock-action:version" fails because ["mock-action:version" is required]]]]]`
+    );
   });
 
-  checkPrivilegesAtSpacesTest(
-    `successful when checking for two actions at two spaces and user has it all`,
-    {
+  test(`successful when checking for two actions at two spaces and user has it all`, async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: [
         `saved_object:${savedObjectTypes[0]}/get`,
@@ -490,26 +516,39 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectedResult: {
-        hasAllRequested: true,
-        username: 'foo-username',
-        spacePrivileges: {
-          space_1: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": true,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_1",
           },
-          space_2: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_1",
           },
-        },
-      },
-    }
-  );
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_2",
+          },
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_2",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
+  });
 
-  checkPrivilegesAtSpacesTest(
-    `failure when checking for two actions at two spaces and user has one action at one space`,
-    {
+  test(`failure when checking for two actions at two spaces and user has one action at one space`, async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: [
         `saved_object:${savedObjectTypes[0]}/get`,
@@ -535,26 +574,39 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectedResult: {
-        hasAllRequested: false,
-        username: 'foo-username',
-        spacePrivileges: {
-          space_1: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: false,
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_1",
           },
-          space_2: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: false,
-            [`saved_object:${savedObjectTypes[1]}/get`]: false,
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_1",
           },
-        },
-      },
-    }
-  );
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_2",
+          },
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_2",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
+  });
 
-  checkPrivilegesAtSpacesTest(
-    `failure when checking for two actions at two spaces and user has two actions at one space`,
-    {
+  test(`failure when checking for two actions at two spaces and user has two actions at one space`, async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: [
         `saved_object:${savedObjectTypes[0]}/get`,
@@ -580,26 +632,39 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectedResult: {
-        hasAllRequested: false,
-        username: 'foo-username',
-        spacePrivileges: {
-          space_1: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_1",
           },
-          space_2: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: false,
-            [`saved_object:${savedObjectTypes[1]}/get`]: false,
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_1",
           },
-        },
-      },
-    }
-  );
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_2",
+          },
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_2",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
+  });
 
-  checkPrivilegesAtSpacesTest(
-    `failure when checking for two actions at two spaces and user has two actions at one space & one action at the other`,
-    {
+  test(`failure when checking for two actions at two spaces and user has two actions at one space & one action at the other`, async () => {
+    const result = await checkPrivilegesAtSpacesTest({
       spaceIds: ['space_1', 'space_2'],
       privilegeOrPrivileges: [
         `saved_object:${savedObjectTypes[0]}/get`,
@@ -625,27 +690,40 @@ describe('#atSpaces', () => {
           },
         },
       },
-      expectedResult: {
-        hasAllRequested: false,
-        username: 'foo-username',
-        spacePrivileges: {
-          space_1: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_1",
           },
-          space_2: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: false,
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_1",
           },
-        },
-      },
-    }
-  );
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": "space_2",
+          },
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:bar-type/get",
+            "resource": "space_2",
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
+  });
 
   describe('with a malformed Elasticsearch response', () => {
-    checkPrivilegesAtSpacesTest(
-      `throws a validation error when an extra privilege is present in the response`,
-      {
+    test(`throws a validation error when an extra privilege is present in the response`, async () => {
+      const result = await checkPrivilegesAtSpacesTest({
         spaceIds: ['space_1', 'space_2'],
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
@@ -668,13 +746,14 @@ describe('#atSpaces', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`
+      );
+    });
 
-    checkPrivilegesAtSpacesTest(
-      `throws a validation error when privileges are missing in the response`,
-      {
+    test(`throws a validation error when privileges are missing in the response`, async () => {
+      const result = await checkPrivilegesAtSpacesTest({
         spaceIds: ['space_1', 'space_2'],
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
@@ -695,13 +774,14 @@ describe('#atSpaces', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`
+      );
+    });
 
-    checkPrivilegesAtSpacesTest(
-      `throws a validation error when an extra space is present in the response`,
-      {
+    test(`throws a validation error when an extra space is present in the response`, async () => {
+      const result = await checkPrivilegesAtSpacesTest({
         spaceIds: ['space_1', 'space_2'],
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
@@ -727,13 +807,14 @@ describe('#atSpaces', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because ["space:space_3" is not allowed]]]`
+      );
+    });
 
-    checkPrivilegesAtSpacesTest(
-      `throws a validation error when an a space is missing in the response`,
-      {
+    test(`throws a validation error when an a space is missing in the response`, async () => {
+      const result = await checkPrivilegesAtSpacesTest({
         spaceIds: ['space_1', 'space_2'],
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
@@ -749,124 +830,127 @@ describe('#atSpaces', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`
+      );
+    });
   });
 });
 
 describe('#globally', () => {
-  const checkPrivilegesGloballyTest = (
-    description: string,
-    options: {
-      privilegeOrPrivileges: string | string[];
-      esHasPrivilegesResponse: HasPrivilegesResponse;
-      expectedResult?: any;
-      expectErrorThrown?: any;
+  const checkPrivilegesGloballyTest = async (options: {
+    privilegeOrPrivileges: string | string[];
+    esHasPrivilegesResponse: HasPrivilegesResponse;
+  }) => {
+    const { mockClusterClient, mockScopedClusterClient } = createMockClusterClient(
+      options.esHasPrivilegesResponse
+    );
+    const checkPrivilegesWithRequest = checkPrivilegesWithRequestFactory(
+      mockActions,
+      mockClusterClient,
+      application
+    );
+    const request = httpServerMock.createKibanaRequest();
+    const checkPrivileges = checkPrivilegesWithRequest(request);
+
+    let actualResult;
+    let errorThrown = null;
+    try {
+      actualResult = await checkPrivileges.globally(options.privilegeOrPrivileges);
+    } catch (err) {
+      errorThrown = err;
     }
-  ) => {
-    test(description, async () => {
-      const { mockClusterClient, mockScopedClusterClient } = createMockClusterClient(
-        options.esHasPrivilegesResponse
-      );
-      const checkPrivilegesWithRequest = checkPrivilegesWithRequestFactory(
-        mockActions,
-        mockClusterClient,
-        application
-      );
-      const request = httpServerMock.createKibanaRequest();
-      const checkPrivileges = checkPrivilegesWithRequest(request);
-
-      let actualResult;
-      let errorThrown = null;
-      try {
-        actualResult = await checkPrivileges.globally(options.privilegeOrPrivileges);
-      } catch (err) {
-        errorThrown = err;
-      }
 
-      expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request);
-      expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith(
-        'shield.hasPrivileges',
-        {
-          body: {
-            applications: [
-              {
-                application,
-                resources: [GLOBAL_RESOURCE],
-                privileges: uniq([
-                  mockActions.version,
-                  mockActions.login,
-                  ...(Array.isArray(options.privilegeOrPrivileges)
-                    ? options.privilegeOrPrivileges
-                    : [options.privilegeOrPrivileges]),
-                ]),
-              },
-            ],
+    expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request);
+    expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith('shield.hasPrivileges', {
+      body: {
+        applications: [
+          {
+            application,
+            resources: [GLOBAL_RESOURCE],
+            privileges: uniq([
+              mockActions.version,
+              mockActions.login,
+              ...(Array.isArray(options.privilegeOrPrivileges)
+                ? options.privilegeOrPrivileges
+                : [options.privilegeOrPrivileges]),
+            ]),
           },
-        }
-      );
-
-      if (options.expectedResult) {
-        expect(errorThrown).toBeNull();
-        expect(actualResult).toEqual(options.expectedResult);
-      }
-
-      if (options.expectErrorThrown) {
-        expect(errorThrown).toMatchSnapshot();
-      }
+        ],
+      },
     });
+
+    if (errorThrown) {
+      return errorThrown;
+    }
+    return actualResult;
   };
 
-  checkPrivilegesGloballyTest('successful when checking for login and user has login', {
-    privilegeOrPrivileges: mockActions.login,
-    esHasPrivilegesResponse: {
-      has_all_requested: true,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          [GLOBAL_RESOURCE]: {
-            [mockActions.login]: true,
-            [mockActions.version]: true,
+  test('successful when checking for login and user has login', async () => {
+    const result = await checkPrivilegesGloballyTest({
+      privilegeOrPrivileges: mockActions.login,
+      esHasPrivilegesResponse: {
+        has_all_requested: true,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            [GLOBAL_RESOURCE]: {
+              [mockActions.login]: true,
+              [mockActions.version]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: true,
-      username: 'foo-username',
-      privileges: {
-        [mockActions.login]: true,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": true,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "mock-action:login",
+            "resource": undefined,
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
-  checkPrivilegesGloballyTest(`failure when checking for login and user doesn't have login`, {
-    privilegeOrPrivileges: mockActions.login,
-    esHasPrivilegesResponse: {
-      has_all_requested: false,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          [GLOBAL_RESOURCE]: {
-            [mockActions.login]: false,
-            [mockActions.version]: true,
+  test(`failure when checking for login and user doesn't have login`, async () => {
+    const result = await checkPrivilegesGloballyTest({
+      privilegeOrPrivileges: mockActions.login,
+      esHasPrivilegesResponse: {
+        has_all_requested: false,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            [GLOBAL_RESOURCE]: {
+              [mockActions.login]: false,
+              [mockActions.version]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: false,
-      username: 'foo-username',
-      privileges: {
-        [mockActions.login]: false,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": false,
+            "privilege": "mock-action:login",
+            "resource": undefined,
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
-  checkPrivilegesGloballyTest(
-    `throws error when checking for login and user has login but doesn't have version`,
-    {
+  test(`throws error when checking for login and user has login but doesn't have version`, async () => {
+    const result = await checkPrivilegesGloballyTest({
       privilegeOrPrivileges: mockActions.login,
       esHasPrivilegesResponse: {
         has_all_requested: false,
@@ -880,92 +964,121 @@ describe('#globally', () => {
           },
         },
       },
-      expectErrorThrown: true,
-    }
-  );
-
-  checkPrivilegesGloballyTest(`throws error when Elasticsearch returns malformed response`, {
-    privilegeOrPrivileges: [
-      `saved_object:${savedObjectTypes[0]}/get`,
-      `saved_object:${savedObjectTypes[1]}/get`,
-    ],
-    esHasPrivilegesResponse: {
-      has_all_requested: false,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          [GLOBAL_RESOURCE]: {
-            [`saved_object:${savedObjectTypes[0]}/get`]: false,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+    });
+    expect(result).toMatchInlineSnapshot(
+      `[Error: Multiple versions of Kibana are running against the same Elasticsearch cluster, unable to authorize user.]`
+    );
+  });
+
+  test(`throws error when Elasticsearch returns malformed response`, async () => {
+    const result = await checkPrivilegesGloballyTest({
+      privilegeOrPrivileges: [
+        `saved_object:${savedObjectTypes[0]}/get`,
+        `saved_object:${savedObjectTypes[1]}/get`,
+      ],
+      esHasPrivilegesResponse: {
+        has_all_requested: false,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            [GLOBAL_RESOURCE]: {
+              [`saved_object:${savedObjectTypes[0]}/get`]: false,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
           },
         },
       },
-    },
-    expectErrorThrown: true,
+    });
+    expect(result).toMatchInlineSnapshot(
+      `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because [child "mock-action:version" fails because ["mock-action:version" is required]]]]]`
+    );
   });
 
-  checkPrivilegesGloballyTest(`successful when checking for two actions and the user has both`, {
-    privilegeOrPrivileges: [
-      `saved_object:${savedObjectTypes[0]}/get`,
-      `saved_object:${savedObjectTypes[1]}/get`,
-    ],
-    esHasPrivilegesResponse: {
-      has_all_requested: true,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          [GLOBAL_RESOURCE]: {
-            [mockActions.login]: true,
-            [mockActions.version]: true,
-            [`saved_object:${savedObjectTypes[0]}/get`]: true,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+  test(`successful when checking for two actions and the user has both`, async () => {
+    const result = await checkPrivilegesGloballyTest({
+      privilegeOrPrivileges: [
+        `saved_object:${savedObjectTypes[0]}/get`,
+        `saved_object:${savedObjectTypes[1]}/get`,
+      ],
+      esHasPrivilegesResponse: {
+        has_all_requested: true,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            [GLOBAL_RESOURCE]: {
+              [mockActions.login]: true,
+              [mockActions.version]: true,
+              [`saved_object:${savedObjectTypes[0]}/get`]: true,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: true,
-      username: 'foo-username',
-      privileges: {
-        [`saved_object:${savedObjectTypes[0]}/get`]: true,
-        [`saved_object:${savedObjectTypes[1]}/get`]: true,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": true,
+        "privileges": Array [
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:foo-type/get",
+            "resource": undefined,
+          },
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": undefined,
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
-  checkPrivilegesGloballyTest(`failure when checking for two actions and the user has only one`, {
-    privilegeOrPrivileges: [
-      `saved_object:${savedObjectTypes[0]}/get`,
-      `saved_object:${savedObjectTypes[1]}/get`,
-    ],
-    esHasPrivilegesResponse: {
-      has_all_requested: false,
-      username: 'foo-username',
-      application: {
-        [application]: {
-          [GLOBAL_RESOURCE]: {
-            [mockActions.login]: true,
-            [mockActions.version]: true,
-            [`saved_object:${savedObjectTypes[0]}/get`]: false,
-            [`saved_object:${savedObjectTypes[1]}/get`]: true,
+  test(`failure when checking for two actions and the user has only one`, async () => {
+    const result = await checkPrivilegesGloballyTest({
+      privilegeOrPrivileges: [
+        `saved_object:${savedObjectTypes[0]}/get`,
+        `saved_object:${savedObjectTypes[1]}/get`,
+      ],
+      esHasPrivilegesResponse: {
+        has_all_requested: false,
+        username: 'foo-username',
+        application: {
+          [application]: {
+            [GLOBAL_RESOURCE]: {
+              [mockActions.login]: true,
+              [mockActions.version]: true,
+              [`saved_object:${savedObjectTypes[0]}/get`]: false,
+              [`saved_object:${savedObjectTypes[1]}/get`]: true,
+            },
           },
         },
       },
-    },
-    expectedResult: {
-      hasAllRequested: false,
-      username: 'foo-username',
-      privileges: {
-        [`saved_object:${savedObjectTypes[0]}/get`]: false,
-        [`saved_object:${savedObjectTypes[1]}/get`]: true,
-      },
-    },
+    });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "hasAllRequested": false,
+        "privileges": Array [
+          Object {
+            "authorized": false,
+            "privilege": "saved_object:foo-type/get",
+            "resource": undefined,
+          },
+          Object {
+            "authorized": true,
+            "privilege": "saved_object:bar-type/get",
+            "resource": undefined,
+          },
+        ],
+        "username": "foo-username",
+      }
+    `);
   });
 
   describe('with a malformed Elasticsearch response', () => {
-    checkPrivilegesGloballyTest(
-      `throws a validation error when an extra privilege is present in the response`,
-      {
+    test(`throws a validation error when an extra privilege is present in the response`, async () => {
+      const result = await checkPrivilegesGloballyTest({
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
           has_all_requested: false,
@@ -981,13 +1094,14 @@ describe('#globally', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because ["saved_object:bar-type/get" is not allowed]]]]`
+      );
+    });
 
-    checkPrivilegesGloballyTest(
-      `throws a validation error when privileges are missing in the response`,
-      {
+    test(`throws a validation error when privileges are missing in the response`, async () => {
+      const result = await checkPrivilegesGloballyTest({
         privilegeOrPrivileges: [`saved_object:${savedObjectTypes[0]}/get`],
         esHasPrivilegesResponse: {
           has_all_requested: false,
@@ -1001,8 +1115,10 @@ describe('#globally', () => {
             },
           },
         },
-        expectErrorThrown: true,
-      }
-    );
+      });
+      expect(result).toMatchInlineSnapshot(
+        `[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because [child "saved_object:foo-type/get" fails because ["saved_object:foo-type/get" is required]]]]]`
+      );
+    });
   });
 });
diff --git a/x-pack/plugins/security/server/authorization/check_privileges.ts b/x-pack/plugins/security/server/authorization/check_privileges.ts
index 3ef7a8f29a0bf..177a49d6defe9 100644
--- a/x-pack/plugins/security/server/authorization/check_privileges.ts
+++ b/x-pack/plugins/security/server/authorization/check_privileges.ts
@@ -16,32 +16,17 @@ interface CheckPrivilegesActions {
   version: string;
 }
 
-interface CheckPrivilegesAtResourcesResponse {
+export interface CheckPrivilegesResponse {
   hasAllRequested: boolean;
   username: string;
-  resourcePrivileges: {
-    [resource: string]: {
-      [privilege: string]: boolean;
-    };
-  };
-}
-
-export interface CheckPrivilegesAtResourceResponse {
-  hasAllRequested: boolean;
-  username: string;
-  privileges: {
-    [privilege: string]: boolean;
-  };
-}
-
-export interface CheckPrivilegesAtSpacesResponse {
-  hasAllRequested: boolean;
-  username: string;
-  spacePrivileges: {
-    [spaceId: string]: {
-      [privilege: string]: boolean;
-    };
-  };
+  privileges: Array<{
+    /**
+     * If this attribute is undefined, this element is a privilege for the global resource.
+     */
+    resource?: string;
+    privilege: string;
+    authorized: boolean;
+  }>;
 }
 
 export type CheckPrivilegesWithRequest = (request: KibanaRequest) => CheckPrivileges;
@@ -50,12 +35,12 @@ export interface CheckPrivileges {
   atSpace(
     spaceId: string,
     privilegeOrPrivileges: string | string[]
-  ): Promise<CheckPrivilegesAtResourceResponse>;
+  ): Promise<CheckPrivilegesResponse>;
   atSpaces(
     spaceIds: string[],
     privilegeOrPrivileges: string | string[]
-  ): Promise<CheckPrivilegesAtSpacesResponse>;
-  globally(privilegeOrPrivileges: string | string[]): Promise<CheckPrivilegesAtResourceResponse>;
+  ): Promise<CheckPrivilegesResponse>;
+  globally(privilegeOrPrivileges: string | string[]): Promise<CheckPrivilegesResponse>;
 }
 
 export function checkPrivilegesWithRequestFactory(
@@ -75,7 +60,7 @@ export function checkPrivilegesWithRequestFactory(
     const checkPrivilegesAtResources = async (
       resources: string[],
       privilegeOrPrivileges: string | string[]
-    ): Promise<CheckPrivilegesAtResourcesResponse> => {
+    ): Promise<CheckPrivilegesResponse> => {
       const privileges = Array.isArray(privilegeOrPrivileges)
         ? privilegeOrPrivileges
         : [privilegeOrPrivileges];
@@ -106,55 +91,43 @@ export function checkPrivilegesWithRequestFactory(
         );
       }
 
+      // we need to filter out the non requested privileges from the response
+      const resourcePrivileges = transform(applicationPrivilegesResponse, (result, value, key) => {
+        result[key!] = pick(value, privileges);
+      }) as HasPrivilegesResponseApplication;
+      const privilegeArray = Object.entries(resourcePrivileges)
+        .map(([key, val]) => {
+          // we need to turn the resource responses back into the space ids
+          const resource =
+            key !== GLOBAL_RESOURCE ? ResourceSerializer.deserializeSpaceResource(key!) : undefined;
+          return Object.entries(val).map(([privilege, authorized]) => ({
+            resource,
+            privilege,
+            authorized,
+          }));
+        })
+        .flat();
+
       return {
         hasAllRequested: hasPrivilegesResponse.has_all_requested,
         username: hasPrivilegesResponse.username,
-        // we need to filter out the non requested privileges from the response
-        resourcePrivileges: transform(applicationPrivilegesResponse, (result, value, key) => {
-          result[key!] = pick(value, privileges);
-        }),
-      };
-    };
-
-    const checkPrivilegesAtResource = async (
-      resource: string,
-      privilegeOrPrivileges: string | string[]
-    ) => {
-      const { hasAllRequested, username, resourcePrivileges } = await checkPrivilegesAtResources(
-        [resource],
-        privilegeOrPrivileges
-      );
-      return {
-        hasAllRequested,
-        username,
-        privileges: resourcePrivileges[resource],
+        privileges: privilegeArray,
       };
     };
 
     return {
       async atSpace(spaceId: string, privilegeOrPrivileges: string | string[]) {
         const spaceResource = ResourceSerializer.serializeSpaceResource(spaceId);
-        return await checkPrivilegesAtResource(spaceResource, privilegeOrPrivileges);
+        return await checkPrivilegesAtResources([spaceResource], privilegeOrPrivileges);
       },
       async atSpaces(spaceIds: string[], privilegeOrPrivileges: string | string[]) {
         const spaceResources = spaceIds.map(spaceId =>
           ResourceSerializer.serializeSpaceResource(spaceId)
         );
-        const { hasAllRequested, username, resourcePrivileges } = await checkPrivilegesAtResources(
-          spaceResources,
-          privilegeOrPrivileges
-        );
-        return {
-          hasAllRequested,
-          username,
-          // we need to turn the resource responses back into the space ids
-          spacePrivileges: transform(resourcePrivileges, (result, value, key) => {
-            result[ResourceSerializer.deserializeSpaceResource(key!)] = value;
-          }),
-        };
+        return await checkPrivilegesAtResources(spaceResources, privilegeOrPrivileges);
       },
       async globally(privilegeOrPrivileges: string | string[]) {
-        return await checkPrivilegesAtResource(GLOBAL_RESOURCE, privilegeOrPrivileges);
+        return await checkPrivilegesAtResources([GLOBAL_RESOURCE], privilegeOrPrivileges);
       },
     };
   };
diff --git a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts
index 0377dd06eb669..6014bad739e77 100644
--- a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts
+++ b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts
@@ -6,11 +6,11 @@
 
 import { KibanaRequest } from '../../../../../src/core/server';
 import { SpacesService } from '../plugin';
-import { CheckPrivilegesAtResourceResponse, CheckPrivilegesWithRequest } from './check_privileges';
+import { CheckPrivilegesResponse, CheckPrivilegesWithRequest } from './check_privileges';
 
 export type CheckPrivilegesDynamically = (
   privilegeOrPrivileges: string | string[]
-) => Promise<CheckPrivilegesAtResourceResponse>;
+) => Promise<CheckPrivilegesResponse>;
 
 export type CheckPrivilegesDynamicallyWithRequest = (
   request: KibanaRequest
diff --git a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts
index 4618e8e6641fc..43b3824500579 100644
--- a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts
+++ b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts
@@ -7,57 +7,113 @@
 import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges';
 
 import { httpServerMock } from '../../../../../src/core/server/mocks';
+import { CheckPrivileges, CheckPrivilegesWithRequest } from './check_privileges';
+import { SpacesService } from '../plugin';
 
-test(`checkPrivileges.atSpace when spaces is enabled`, async () => {
-  const expectedResult = Symbol();
-  const spaceId = 'foo-space';
-  const mockCheckPrivileges = {
-    atSpace: jest.fn().mockReturnValue(expectedResult),
-  };
-  const mockCheckPrivilegesWithRequest = jest.fn().mockReturnValue(mockCheckPrivileges);
-  const request = httpServerMock.createKibanaRequest();
-  const privilegeOrPrivileges = ['foo', 'bar'];
-  const mockSpacesService = {
-    getSpaceId: jest.fn(),
-    namespaceToSpaceId: jest.fn().mockReturnValue(spaceId),
-  };
+let mockCheckPrivileges: jest.Mocked<CheckPrivileges>;
+let mockCheckPrivilegesWithRequest: jest.Mocked<CheckPrivilegesWithRequest>;
+let mockSpacesService: jest.Mocked<SpacesService> | undefined;
+const request = httpServerMock.createKibanaRequest();
 
-  const checkSavedObjectsPrivileges = checkSavedObjectsPrivilegesWithRequestFactory(
+const createFactory = () =>
+  checkSavedObjectsPrivilegesWithRequestFactory(
     mockCheckPrivilegesWithRequest,
     () => mockSpacesService
   )(request);
 
-  const namespace = 'foo';
-
-  const result = await checkSavedObjectsPrivileges(privilegeOrPrivileges, namespace);
+beforeEach(() => {
+  mockCheckPrivileges = {
+    atSpace: jest.fn(),
+    atSpaces: jest.fn(),
+    globally: jest.fn(),
+  };
+  mockCheckPrivilegesWithRequest = jest.fn().mockReturnValue(mockCheckPrivileges);
 
-  expect(result).toBe(expectedResult);
-  expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledWith(request);
-  expect(mockCheckPrivileges.atSpace).toHaveBeenCalledWith(spaceId, privilegeOrPrivileges);
-  expect(mockSpacesService.namespaceToSpaceId).toBeCalledWith(namespace);
+  mockSpacesService = {
+    getSpaceId: jest.fn(),
+    namespaceToSpaceId: jest.fn().mockImplementation((namespace: string) => `${namespace}-id`),
+  };
 });
 
-test(`checkPrivileges.globally when spaces is disabled`, async () => {
-  const expectedResult = Symbol();
-  const mockCheckPrivileges = {
-    globally: jest.fn().mockReturnValue(expectedResult),
-  };
-  const mockCheckPrivilegesWithRequest = jest.fn().mockReturnValue(mockCheckPrivileges);
+describe('#checkSavedObjectsPrivileges', () => {
+  const actions = ['foo', 'bar'];
+  const namespace1 = 'baz';
+  const namespace2 = 'qux';
 
-  const request = httpServerMock.createKibanaRequest();
+  describe('when checking multiple namespaces', () => {
+    const namespaces = [namespace1, namespace2];
 
-  const privilegeOrPrivileges = ['foo', 'bar'];
+    test(`throws an error when Spaces is disabled`, async () => {
+      mockSpacesService = undefined;
+      const checkSavedObjectsPrivileges = createFactory();
 
-  const checkSavedObjectsPrivileges = checkSavedObjectsPrivilegesWithRequestFactory(
-    mockCheckPrivilegesWithRequest,
-    () => undefined
-  )(request);
+      await expect(
+        checkSavedObjectsPrivileges(actions, namespaces)
+      ).rejects.toThrowErrorMatchingInlineSnapshot(
+        `"Can't check saved object privileges for multiple namespaces if Spaces is disabled"`
+      );
+    });
+
+    test(`throws an error when using an empty namespaces array`, async () => {
+      const checkSavedObjectsPrivileges = createFactory();
+
+      await expect(
+        checkSavedObjectsPrivileges(actions, [])
+      ).rejects.toThrowErrorMatchingInlineSnapshot(
+        `"Can't check saved object privileges for 0 namespaces"`
+      );
+    });
+
+    test(`uses checkPrivileges.atSpaces when spaces is enabled`, async () => {
+      const expectedResult = Symbol();
+      mockCheckPrivileges.atSpaces.mockReturnValue(expectedResult as any);
+      const checkSavedObjectsPrivileges = createFactory();
+
+      const result = await checkSavedObjectsPrivileges(actions, namespaces);
+
+      expect(result).toBe(expectedResult);
+      expect(mockSpacesService!.namespaceToSpaceId).toHaveBeenCalledTimes(2);
+      expect(mockSpacesService!.namespaceToSpaceId).toHaveBeenNthCalledWith(1, namespace1);
+      expect(mockSpacesService!.namespaceToSpaceId).toHaveBeenNthCalledWith(2, namespace2);
+      expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledTimes(1);
+      expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledWith(request);
+      expect(mockCheckPrivileges.atSpaces).toHaveBeenCalledTimes(1);
+      const spaceIds = mockSpacesService!.namespaceToSpaceId.mock.results.map(x => x.value);
+      expect(mockCheckPrivileges.atSpaces).toHaveBeenCalledWith(spaceIds, actions);
+    });
+  });
+
+  describe('when checking a single namespace', () => {
+    test(`uses checkPrivileges.atSpace when Spaces is enabled`, async () => {
+      const expectedResult = Symbol();
+      mockCheckPrivileges.atSpace.mockReturnValue(expectedResult as any);
+      const checkSavedObjectsPrivileges = createFactory();
+
+      const result = await checkSavedObjectsPrivileges(actions, namespace1);
+
+      expect(result).toBe(expectedResult);
+      expect(mockSpacesService!.namespaceToSpaceId).toHaveBeenCalledTimes(1);
+      expect(mockSpacesService!.namespaceToSpaceId).toHaveBeenCalledWith(namespace1);
+      expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledTimes(1);
+      expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledWith(request);
+      expect(mockCheckPrivileges.atSpace).toHaveBeenCalledTimes(1);
+      const spaceId = mockSpacesService!.namespaceToSpaceId.mock.results[0].value;
+      expect(mockCheckPrivileges.atSpace).toHaveBeenCalledWith(spaceId, actions);
+    });
 
-  const namespace = 'foo';
+    test(`uses checkPrivileges.globally when Spaces is disabled`, async () => {
+      const expectedResult = Symbol();
+      mockCheckPrivileges.globally.mockReturnValue(expectedResult as any);
+      mockSpacesService = undefined;
+      const checkSavedObjectsPrivileges = createFactory();
 
-  const result = await checkSavedObjectsPrivileges(privilegeOrPrivileges, namespace);
+      const result = await checkSavedObjectsPrivileges(actions, namespace1);
 
-  expect(result).toBe(expectedResult);
-  expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledWith(request);
-  expect(mockCheckPrivileges.globally).toHaveBeenCalledWith(privilegeOrPrivileges);
+      expect(result).toBe(expectedResult);
+      expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledTimes(1);
+      expect(mockCheckPrivilegesWithRequest).toHaveBeenCalledWith(request);
+      expect(mockCheckPrivileges.globally).toHaveBeenCalledTimes(1);
+      expect(mockCheckPrivileges.globally).toHaveBeenCalledWith(actions);
+    });
+  });
 });
diff --git a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts
index 02958fe265efa..43140143a1773 100644
--- a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts
+++ b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts
@@ -6,32 +6,44 @@
 
 import { KibanaRequest } from '../../../../../src/core/server';
 import { SpacesService } from '../plugin';
-import { CheckPrivilegesAtResourceResponse, CheckPrivilegesWithRequest } from './check_privileges';
+import { CheckPrivilegesWithRequest, CheckPrivilegesResponse } from './check_privileges';
 
 export type CheckSavedObjectsPrivilegesWithRequest = (
   request: KibanaRequest
 ) => CheckSavedObjectsPrivileges;
+
 export type CheckSavedObjectsPrivileges = (
   actions: string | string[],
-  namespace?: string
-) => Promise<CheckPrivilegesAtResourceResponse>;
+  namespaceOrNamespaces?: string | string[]
+) => Promise<CheckPrivilegesResponse>;
 
 export const checkSavedObjectsPrivilegesWithRequestFactory = (
   checkPrivilegesWithRequest: CheckPrivilegesWithRequest,
   getSpacesService: () => SpacesService | undefined
 ): CheckSavedObjectsPrivilegesWithRequest => {
-  return function checkSavedObjectsPrivilegesWithRequest(request: KibanaRequest) {
+  return function checkSavedObjectsPrivilegesWithRequest(
+    request: KibanaRequest
+  ): CheckSavedObjectsPrivileges {
     return async function checkSavedObjectsPrivileges(
       actions: string | string[],
-      namespace?: string
+      namespaceOrNamespaces?: string | string[]
     ) {
       const spacesService = getSpacesService();
-      return spacesService
-        ? await checkPrivilegesWithRequest(request).atSpace(
-            spacesService.namespaceToSpaceId(namespace),
-            actions
-          )
-        : await checkPrivilegesWithRequest(request).globally(actions);
+      if (Array.isArray(namespaceOrNamespaces)) {
+        if (spacesService === undefined) {
+          throw new Error(
+            `Can't check saved object privileges for multiple namespaces if Spaces is disabled`
+          );
+        } else if (!namespaceOrNamespaces.length) {
+          throw new Error(`Can't check saved object privileges for 0 namespaces`);
+        }
+        const spaceIds = namespaceOrNamespaces.map(x => spacesService.namespaceToSpaceId(x));
+        return await checkPrivilegesWithRequest(request).atSpaces(spaceIds, actions);
+      } else if (spacesService) {
+        const spaceId = spacesService.namespaceToSpaceId(namespaceOrNamespaces);
+        return await checkPrivilegesWithRequest(request).atSpace(spaceId, actions);
+      }
+      return await checkPrivilegesWithRequest(request).globally(actions);
     };
   };
 };
diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts
index 912ae60e12065..ea97a1b3b590c 100644
--- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts
+++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts
@@ -11,7 +11,9 @@ import { httpServerMock, loggingServiceMock } from '../../../../../src/core/serv
 import { authorizationMock } from './index.mock';
 import { Feature } from '../../../features/server';
 
-type MockAuthzOptions = { rejectCheckPrivileges: any } | { resolveCheckPrivileges: any };
+type MockAuthzOptions =
+  | { rejectCheckPrivileges: any }
+  | { resolveCheckPrivileges: { privileges: Array<{ privilege: string; authorized: boolean }> } };
 
 const actions = new Actions('1.0.0-zeta1');
 const mockRequest = httpServerMock.createKibanaRequest();
@@ -26,7 +28,8 @@ const createMockAuthz = (options: MockAuthzOptions) => {
         throw options.rejectCheckPrivileges;
       }
 
-      expect(checkActions).toEqual(Object.keys(options.resolveCheckPrivileges.privileges));
+      const expected = options.resolveCheckPrivileges.privileges.map(x => x.privilege);
+      expect(checkActions).toEqual(expected);
       return options.resolveCheckPrivileges;
     });
   });
@@ -226,17 +229,17 @@ describe('usingPrivileges', () => {
   test(`disables ui capabilities when they don't have privileges`, async () => {
     const mockAuthz = createMockAuthz({
       resolveCheckPrivileges: {
-        privileges: {
-          [actions.ui.get('navLinks', 'foo')]: true,
-          [actions.ui.get('navLinks', 'bar')]: false,
-          [actions.ui.get('navLinks', 'quz')]: false,
-          [actions.ui.get('management', 'kibana', 'indices')]: true,
-          [actions.ui.get('management', 'kibana', 'settings')]: false,
-          [actions.ui.get('fooFeature', 'foo')]: true,
-          [actions.ui.get('fooFeature', 'bar')]: false,
-          [actions.ui.get('barFeature', 'foo')]: true,
-          [actions.ui.get('barFeature', 'bar')]: false,
-        },
+        privileges: [
+          { privilege: actions.ui.get('navLinks', 'foo'), authorized: true },
+          { privilege: actions.ui.get('navLinks', 'bar'), authorized: false },
+          { privilege: actions.ui.get('navLinks', 'quz'), authorized: false },
+          { privilege: actions.ui.get('management', 'kibana', 'indices'), authorized: true },
+          { privilege: actions.ui.get('management', 'kibana', 'settings'), authorized: false },
+          { privilege: actions.ui.get('fooFeature', 'foo'), authorized: true },
+          { privilege: actions.ui.get('fooFeature', 'bar'), authorized: false },
+          { privilege: actions.ui.get('barFeature', 'foo'), authorized: true },
+          { privilege: actions.ui.get('barFeature', 'bar'), authorized: false },
+        ],
       },
     });
 
@@ -314,15 +317,15 @@ describe('usingPrivileges', () => {
   test(`doesn't re-enable disabled uiCapabilities`, async () => {
     const mockAuthz = createMockAuthz({
       resolveCheckPrivileges: {
-        privileges: {
-          [actions.ui.get('navLinks', 'foo')]: true,
-          [actions.ui.get('navLinks', 'bar')]: true,
-          [actions.ui.get('management', 'kibana', 'indices')]: true,
-          [actions.ui.get('fooFeature', 'foo')]: true,
-          [actions.ui.get('fooFeature', 'bar')]: true,
-          [actions.ui.get('barFeature', 'foo')]: true,
-          [actions.ui.get('barFeature', 'bar')]: true,
-        },
+        privileges: [
+          { privilege: actions.ui.get('navLinks', 'foo'), authorized: true },
+          { privilege: actions.ui.get('navLinks', 'bar'), authorized: true },
+          { privilege: actions.ui.get('management', 'kibana', 'indices'), authorized: true },
+          { privilege: actions.ui.get('fooFeature', 'foo'), authorized: true },
+          { privilege: actions.ui.get('fooFeature', 'bar'), authorized: true },
+          { privilege: actions.ui.get('barFeature', 'foo'), authorized: true },
+          { privilege: actions.ui.get('barFeature', 'bar'), authorized: true },
+        ],
       },
     });
 
diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts
index be26f52fbf756..f0f1a42ad0bd5 100644
--- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts
+++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts
@@ -9,7 +9,7 @@ import { UICapabilities } from 'ui/capabilities';
 import { KibanaRequest, Logger } from '../../../../../src/core/server';
 import { Feature } from '../../../features/server';
 
-import { CheckPrivilegesAtResourceResponse } from './check_privileges';
+import { CheckPrivilegesResponse } from './check_privileges';
 import { Authorization } from './index';
 
 export function disableUICapabilitiesFactory(
@@ -77,7 +77,7 @@ export function disableUICapabilitiesFactory(
       []
     );
 
-    let checkPrivilegesResponse: CheckPrivilegesAtResourceResponse;
+    let checkPrivilegesResponse: CheckPrivilegesResponse;
     try {
       const checkPrivilegesDynamically = authz.checkPrivilegesDynamicallyWithRequest(request);
       checkPrivilegesResponse = await checkPrivilegesDynamically(uiActions);
@@ -105,7 +105,9 @@ export function disableUICapabilitiesFactory(
       }
 
       const action = authz.actions.ui.get(featureId, ...uiCapabilityParts);
-      return checkPrivilegesResponse.privileges[action] === true;
+      return checkPrivilegesResponse.privileges.some(
+        x => x.privilege === action && x.authorized === true
+      );
     };
 
     return mapValues(uiCapabilities, (featureUICapabilities, featureId) => {
diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts
index 032d231fe798f..68acf68f46109 100644
--- a/x-pack/plugins/security/server/plugin.ts
+++ b/x-pack/plugins/security/server/plugin.ts
@@ -149,6 +149,7 @@ export class Plugin {
       auditLogger: new SecurityAuditLogger(() => this.getLegacyAPI().auditLogger),
       authz,
       savedObjects: core.savedObjects,
+      getSpacesService: this.getSpacesService,
     });
 
     core.capabilities.registerSwitcher(authz.disableUnauthorizedCapabilities);
diff --git a/x-pack/plugins/security/server/saved_objects/index.ts b/x-pack/plugins/security/server/saved_objects/index.ts
index 5954729562847..7dac745fcf84b 100644
--- a/x-pack/plugins/security/server/saved_objects/index.ts
+++ b/x-pack/plugins/security/server/saved_objects/index.ts
@@ -13,14 +13,21 @@ import {
 import { SecureSavedObjectsClientWrapper } from './secure_saved_objects_client_wrapper';
 import { Authorization } from '../authorization';
 import { SecurityAuditLogger } from '../audit';
+import { SpacesService } from '../plugin';
 
 interface SetupSavedObjectsParams {
   auditLogger: SecurityAuditLogger;
   authz: Pick<Authorization, 'mode' | 'actions' | 'checkSavedObjectsPrivilegesWithRequest'>;
   savedObjects: CoreSetup['savedObjects'];
+  getSpacesService(): SpacesService | undefined;
 }
 
-export function setupSavedObjects({ auditLogger, authz, savedObjects }: SetupSavedObjectsParams) {
+export function setupSavedObjects({
+  auditLogger,
+  authz,
+  savedObjects,
+  getSpacesService,
+}: SetupSavedObjectsParams) {
   const getKibanaRequest = (request: KibanaRequest | LegacyRequest) =>
     request instanceof KibanaRequest ? request : KibanaRequest.from(request);
 
@@ -44,6 +51,7 @@ export function setupSavedObjects({ auditLogger, authz, savedObjects }: SetupSav
             kibanaRequest
           ),
           errors: SavedObjectsClient.errors,
+          getSpacesService,
         })
       : client;
   });
diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts
index 3c04508e3a74a..3c4034e07f995 100644
--- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts
+++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts
@@ -9,6 +9,11 @@ import { Actions } from '../authorization';
 import { securityAuditLoggerMock } from '../audit/index.mock';
 import { savedObjectsClientMock } from '../../../../../src/core/server/mocks';
 import { SavedObjectsClientContract } from 'kibana/server';
+import { SavedObjectActions } from '../authorization/actions/saved_object';
+
+let clientOpts: ReturnType<typeof createSecureSavedObjectsClientWrapperOptions>;
+let client: SecureSavedObjectsClientWrapper;
+const USERNAME = Symbol();
 
 const createSecureSavedObjectsClientWrapperOptions = () => {
   const actions = new Actions('some-version');
@@ -22,810 +27,677 @@ const createSecureSavedObjectsClientWrapperOptions = () => {
   const errors = ({
     decorateForbiddenError: jest.fn().mockReturnValue(forbiddenError),
     decorateGeneralError: jest.fn().mockReturnValue(generalError),
+    isNotFoundError: jest.fn().mockReturnValue(false),
   } as unknown) as jest.Mocked<SavedObjectsClientContract['errors']>;
+  const getSpacesService = jest.fn().mockReturnValue(true);
 
   return {
     actions,
     baseClient: savedObjectsClientMock.create(),
     checkSavedObjectsPrivilegesAsCurrentUser: jest.fn(),
     errors,
+    getSpacesService,
     auditLogger: securityAuditLoggerMock.create(),
     forbiddenError,
     generalError,
   };
 };
 
-describe('#errors', () => {
-  test(`assigns errors from constructor to .errors`, () => {
-    const options = createSecureSavedObjectsClientWrapperOptions();
-    const client = new SecureSavedObjectsClientWrapper(options);
+const expectGeneralError = async (fn: Function, args: Record<string, any>) => {
+  // mock the checkPrivileges.globally rejection
+  const rejection = new Error('An actual error would happen here');
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(rejection);
+
+  await expect(fn.bind(client)(...Object.values(args))).rejects.toThrowError(
+    clientOpts.generalError
+  );
+  expect(clientOpts.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
+};
+
+/**
+ * Fails the first authorization check, passes any others
+ * Requires that function args are passed in as key/value pairs
+ * The argument properties must be in the correct order to be spread properly
+ */
+const expectForbiddenError = async (fn: Function, args: Record<string, any>) => {
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+    getMockCheckPrivilegesFailure
+  );
+
+  await expect(fn.bind(client)(...Object.values(args))).rejects.toThrowError(
+    clientOpts.forbiddenError
+  );
+  const getCalls = (clientOpts.actions.savedObject.get as jest.MockedFunction<
+    SavedObjectActions['get']
+  >).mock.calls;
+  const actions = clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mock.calls[0][0];
+  const spaceId = args.options?.namespace || 'default';
+
+  const ACTION = getCalls[0][1];
+  const types = getCalls.map(x => x[0]);
+  const missing = [{ spaceId, privilege: actions[0] }]; // if there was more than one type, only the first type was unauthorized
+  const spaceIds = [spaceId];
+
+  expect(clientOpts.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledTimes(1);
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
+    USERNAME,
+    ACTION,
+    types,
+    spaceIds,
+    missing,
+    args
+  );
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
+};
+
+const expectSuccess = async (fn: Function, args: Record<string, any>) => {
+  const result = await fn.bind(client)(...Object.values(args));
+  const getCalls = (clientOpts.actions.savedObject.get as jest.MockedFunction<
+    SavedObjectActions['get']
+  >).mock.calls;
+  const ACTION = getCalls[0][1];
+  const types = getCalls.map(x => x[0]);
+  const spaceIds = [args.options?.namespace || 'default'];
+
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledTimes(1);
+  expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
+    USERNAME,
+    ACTION,
+    types,
+    spaceIds,
+    args
+  );
+  return result;
+};
+
+const expectPrivilegeCheck = async (fn: Function, args: Record<string, any>) => {
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+    getMockCheckPrivilegesFailure
+  );
+
+  await expect(fn.bind(client)(...Object.values(args))).rejects.toThrow(); // test is simpler with error case
+  const getResults = (clientOpts.actions.savedObject.get as jest.MockedFunction<
+    SavedObjectActions['get']
+  >).mock.results;
+  const actions = getResults.map(x => x.value);
+
+  expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledTimes(1);
+  expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
+    actions,
+    args.options?.namespace
+  );
+};
+
+const expectObjectNamespaceFiltering = async (fn: Function, args: Record<string, any>) => {
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementationOnce(
+    getMockCheckPrivilegesSuccess // privilege check for authorization
+  );
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+    getMockCheckPrivilegesFailure // privilege check for namespace filtering
+  );
+
+  const authorizedNamespace = args.options.namespace || 'default';
+  const namespaces = ['some-other-namespace', authorizedNamespace];
+  const returnValue = { namespaces, foo: 'bar' };
+  // we don't know which base client method will be called; mock them all
+  clientOpts.baseClient.create.mockReturnValue(returnValue as any);
+  clientOpts.baseClient.get.mockReturnValue(returnValue as any);
+  clientOpts.baseClient.update.mockReturnValue(returnValue as any);
+
+  const result = await fn.bind(client)(...Object.values(args));
+  expect(result).toEqual(expect.objectContaining({ namespaces: [authorizedNamespace, '?'] }));
+
+  expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledTimes(2);
+  expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenLastCalledWith(
+    'login:',
+    namespaces
+  );
+};
+
+const expectObjectsNamespaceFiltering = async (fn: Function, args: Record<string, any>) => {
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementationOnce(
+    getMockCheckPrivilegesSuccess // privilege check for authorization
+  );
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+    getMockCheckPrivilegesFailure // privilege check for namespace filtering
+  );
+
+  const authorizedNamespace = args.options.namespace || 'default';
+  const returnValue = {
+    saved_objects: [
+      { namespaces: ['foo'] },
+      { namespaces: [authorizedNamespace] },
+      { namespaces: ['foo', authorizedNamespace] },
+    ],
+  };
+
+  // we don't know which base client method will be called; mock them all
+  clientOpts.baseClient.bulkCreate.mockReturnValue(returnValue as any);
+  clientOpts.baseClient.bulkGet.mockReturnValue(returnValue as any);
+  clientOpts.baseClient.bulkUpdate.mockReturnValue(returnValue as any);
+  clientOpts.baseClient.find.mockReturnValue(returnValue as any);
+
+  const result = await fn.bind(client)(...Object.values(args));
+  expect(result).toEqual(
+    expect.objectContaining({
+      saved_objects: [
+        { namespaces: ['?'] },
+        { namespaces: [authorizedNamespace] },
+        { namespaces: [authorizedNamespace, '?'] },
+      ],
+    })
+  );
+
+  expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledTimes(2);
+  expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenLastCalledWith('login:', [
+    'foo',
+    authorizedNamespace,
+  ]);
+};
+
+function getMockCheckPrivilegesSuccess(actions: string | string[], namespaces?: string | string[]) {
+  const _namespaces = Array.isArray(namespaces) ? namespaces : [namespaces || 'default'];
+  const _actions = Array.isArray(actions) ? actions : [actions];
+  return {
+    hasAllRequested: true,
+    username: USERNAME,
+    privileges: _namespaces
+      .map(resource =>
+        _actions.map(action => ({
+          resource,
+          privilege: action,
+          authorized: true,
+        }))
+      )
+      .flat(),
+  };
+}
+
+/**
+ * Fails the authorization check for the first privilege, and passes any others
+ * This check may be for an action for two different types in the same namespace
+ * Or, it may be for an action for the same type in two different namespaces
+ * Either way, the first privilege check returned is false, and any others return true
+ */
+function getMockCheckPrivilegesFailure(actions: string | string[], namespaces?: string | string[]) {
+  const _namespaces = Array.isArray(namespaces) ? namespaces : [namespaces || 'default'];
+  const _actions = Array.isArray(actions) ? actions : [actions];
+  return {
+    hasAllRequested: false,
+    username: USERNAME,
+    privileges: _namespaces
+      .map((resource, idxa) =>
+        _actions.map((action, idxb) => ({
+          resource,
+          privilege: action,
+          authorized: idxa > 0 || idxb > 0,
+        }))
+      )
+      .flat(),
+  };
+}
+
+/**
+ * Before each test, create the Client with its Options
+ */
+beforeEach(() => {
+  clientOpts = createSecureSavedObjectsClientWrapperOptions();
+  client = new SecureSavedObjectsClientWrapper(clientOpts);
+
+  // succeed privilege checks by default
+  clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+    getMockCheckPrivilegesSuccess
+  );
+});
+
+describe('#addToNamespaces', () => {
+  const type = 'foo';
+  const id = `${type}-id`;
+  const newNs1 = 'foo-namespace';
+  const newNs2 = 'bar-namespace';
+  const namespaces = [newNs1, newNs2];
+  const currentNs = 'default';
+  const privilege1 = `mock-saved_object:${type}/create`;
+  const privilege2 = `mock-saved_object:${type}/update`;
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    await expectGeneralError(client.addToNamespaces, { type, id, namespaces });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized to create in new space`, async () => {
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+      getMockCheckPrivilegesFailure
+    );
+
+    await expect(client.addToNamespaces(type, id, namespaces)).rejects.toThrowError(
+      clientOpts.forbiddenError
+    );
+
+    expect(clientOpts.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledTimes(1);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
+      USERNAME,
+      'addToNamespacesCreate',
+      [type],
+      namespaces.sort(),
+      [{ privilege: privilege1, spaceId: newNs1 }],
+      { id, type, namespaces, options: {} }
+    );
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized to update in current space`, async () => {
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementationOnce(
+      getMockCheckPrivilegesSuccess // create
+    );
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+      getMockCheckPrivilegesFailure // update
+    );
+
+    await expect(client.addToNamespaces(type, id, namespaces)).rejects.toThrowError(
+      clientOpts.forbiddenError
+    );
+
+    expect(clientOpts.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledTimes(1);
+    expect(
+      clientOpts.auditLogger.savedObjectsAuthorizationFailure
+    ).toHaveBeenLastCalledWith(
+      USERNAME,
+      'addToNamespacesUpdate',
+      [type],
+      [currentNs],
+      [{ privilege: privilege2, spaceId: currentNs }],
+      { id, type, namespaces, options: {} }
+    );
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledTimes(1);
+  });
+
+  test(`returns result of baseClient.addToNamespaces when authorized`, async () => {
+    const apiCallReturnValue = Symbol();
+    clientOpts.baseClient.addToNamespaces.mockReturnValue(apiCallReturnValue as any);
+
+    const result = await client.addToNamespaces(type, id, namespaces);
+    expect(result).toBe(apiCallReturnValue);
+
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledTimes(2);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenNthCalledWith(
+      1,
+      USERNAME,
+      'addToNamespacesCreate', // action for privilege check is 'create', but auditAction is 'addToNamespacesCreate'
+      [type],
+      namespaces.sort(),
+      { type, id, namespaces, options: {} }
+    );
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenNthCalledWith(
+      2,
+      USERNAME,
+      'addToNamespacesUpdate', // action for privilege check is 'update', but auditAction is 'addToNamespacesUpdate'
+      [type],
+      [currentNs],
+      { type, id, namespaces, options: {} }
+    );
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementationOnce(
+      getMockCheckPrivilegesSuccess // create
+    );
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+      getMockCheckPrivilegesFailure // update
+    );
+
+    await expect(client.addToNamespaces(type, id, namespaces)).rejects.toThrow(); // test is simpler with error case
+
+    expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledTimes(2);
+    expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenNthCalledWith(
+      1,
+      [privilege1],
+      namespaces
+    );
+    expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenNthCalledWith(
+      2,
+      [privilege2],
+      undefined // default namespace
+    );
+  });
+});
+
+describe('#bulkCreate', () => {
+  const attributes = { some: 'attr' };
+  const obj1 = Object.freeze({ type: 'foo', otherThing: 'sup', attributes });
+  const obj2 = Object.freeze({ type: 'bar', otherThing: 'everyone', attributes });
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    const objects = [obj1];
+    await expectGeneralError(client.bulkCreate, { objects });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    const objects = [obj1, obj2];
+    await expectForbiddenError(client.bulkCreate, { objects, options });
+  });
+
+  test(`returns result of baseClient.bulkCreate when authorized`, async () => {
+    const apiCallReturnValue = { saved_objects: [], foo: 'bar' };
+    clientOpts.baseClient.bulkCreate.mockReturnValue(apiCallReturnValue as any);
+
+    const objects = [obj1, obj2];
+    const result = await expectSuccess(client.bulkCreate, { objects, options });
+    expect(result).toEqual(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    const objects = [obj1, obj2];
+    await expectPrivilegeCheck(client.bulkCreate, { objects, options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    const objects = [obj1, obj2];
+    await expectObjectsNamespaceFiltering(client.bulkCreate, { objects, options });
+  });
+});
+
+describe('#bulkGet', () => {
+  const obj1 = Object.freeze({ type: 'foo', id: 'foo-id' });
+  const obj2 = Object.freeze({ type: 'bar', id: 'bar-id' });
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    const objects = [obj1];
+    await expectGeneralError(client.bulkGet, { objects });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    const objects = [obj1, obj2];
+    await expectForbiddenError(client.bulkGet, { objects, options });
+  });
+
+  test(`returns result of baseClient.bulkGet when authorized`, async () => {
+    const apiCallReturnValue = { saved_objects: [], foo: 'bar' };
+    clientOpts.baseClient.bulkGet.mockReturnValue(apiCallReturnValue as any);
+
+    const objects = [obj1, obj2];
+    const result = await expectSuccess(client.bulkGet, { objects, options });
+    expect(result).toEqual(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    const objects = [obj1, obj2];
+    await expectPrivilegeCheck(client.bulkGet, { objects, options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    const objects = [obj1, obj2];
+    await expectObjectsNamespaceFiltering(client.bulkGet, { objects, options });
+  });
+});
+
+describe('#bulkUpdate', () => {
+  const obj1 = Object.freeze({ type: 'foo', id: 'foo-id', attributes: { some: 'attr' } });
+  const obj2 = Object.freeze({ type: 'bar', id: 'bar-id', attributes: { other: 'attr' } });
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    const objects = [obj1];
+    await expectGeneralError(client.bulkUpdate, { objects });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    const objects = [obj1, obj2];
+    await expectForbiddenError(client.bulkUpdate, { objects, options });
+  });
+
+  test(`returns result of baseClient.bulkUpdate when authorized`, async () => {
+    const apiCallReturnValue = { saved_objects: [], foo: 'bar' };
+    clientOpts.baseClient.bulkUpdate.mockReturnValue(apiCallReturnValue as any);
+
+    const objects = [obj1, obj2];
+    const result = await expectSuccess(client.bulkUpdate, { objects, options });
+    expect(result).toEqual(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    const objects = [obj1, obj2];
+    await expectPrivilegeCheck(client.bulkUpdate, { objects, options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    const objects = [obj1, obj2];
+    await expectObjectsNamespaceFiltering(client.bulkUpdate, { objects, options });
+  });
+});
+
+describe('#create', () => {
+  const type = 'foo';
+  const attributes = { some_attr: 's' };
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when checkPrivileges.globally rejects promise`, async () => {
+    await expectGeneralError(client.create, { type });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    await expectForbiddenError(client.create, { type, attributes, options });
+  });
+
+  test(`returns result of baseClient.create when authorized`, async () => {
+    const apiCallReturnValue = Symbol();
+    clientOpts.baseClient.create.mockResolvedValue(apiCallReturnValue as any);
+
+    const result = await expectSuccess(client.create, { type, attributes, options });
+    expect(result).toBe(apiCallReturnValue);
+  });
 
-    expect(client.errors).toBe(options.errors);
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    await expectPrivilegeCheck(client.create, { type, attributes, options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    await expectObjectNamespaceFiltering(client.create, { type, attributes, options });
   });
 });
 
-describe(`spaces disabled`, () => {
-  describe('#create', () => {
-    test(`throws decorated GeneralError when checkPrivileges.globally rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.create(type)).rejects.toThrowError(options.generalError);
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'create')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type = 'foo';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'create')]: false },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const attributes = { some_attr: 's' };
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.create(type, attributes, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'create')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'create',
-        [type],
-        [options.actions.savedObject.get(type, 'create')],
-        { type, attributes, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.create when authorized`, async () => {
-      const type = 'foo';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'create')]: true },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.create.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const attributes = { some_attr: 's' };
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.create(type, attributes, apiCallOptions)).resolves.toBe(
-        apiCallReturnValue
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'create')],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.create).toHaveBeenCalledWith(type, attributes, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'create',
-        [type],
-        { type, attributes, options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#bulkCreate', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(
-        client.bulkCreate([{ type, attributes: {} }], apiCallOptions)
-      ).rejects.toThrowError(options.generalError);
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'bulk_create')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type1 = 'foo';
-      const type2 = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type1, 'bulk_create')]: false,
-          [options.actions.savedObject.get(type2, 'bulk_create')]: true,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const objects = [
-        { type: type1, attributes: {} },
-        { type: type2, attributes: {} },
-      ];
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.bulkCreate(objects, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [
-          options.actions.savedObject.get(type1, 'bulk_create'),
-          options.actions.savedObject.get(type2, 'bulk_create'),
-        ],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'bulk_create',
-        [type1, type2],
-        [options.actions.savedObject.get(type1, 'bulk_create')],
-        { objects, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.bulkCreate when authorized`, async () => {
-      const type1 = 'foo';
-      const type2 = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type1, 'bulk_create')]: true,
-          [options.actions.savedObject.get(type2, 'bulk_create')]: true,
-        },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.bulkCreate.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const objects = [
-        { type: type1, otherThing: 'sup', attributes: {} },
-        { type: type2, otherThing: 'everyone', attributes: {} },
-      ];
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.bulkCreate(objects, apiCallOptions)).resolves.toBe(apiCallReturnValue);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [
-          options.actions.savedObject.get(type1, 'bulk_create'),
-          options.actions.savedObject.get(type2, 'bulk_create'),
-        ],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.bulkCreate).toHaveBeenCalledWith(objects, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'bulk_create',
-        [type1, type2],
-        { objects, options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#delete', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.delete(type, 'bar')).rejects.toThrowError(options.generalError);
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'delete')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type = 'foo';
-      const id = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type, 'delete')]: false,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.delete(type, id, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'delete')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'delete',
-        [type],
-        [options.actions.savedObject.get(type, 'delete')],
-        { type, id, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of internalRepository.delete when authorized`, async () => {
-      const type = 'foo';
-      const id = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'delete')]: true },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.delete.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.delete(type, id, apiCallOptions)).resolves.toBe(apiCallReturnValue);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'delete')],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.delete).toHaveBeenCalledWith(type, id, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'delete',
-        [type],
-        { type, id, options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#find', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.find({ type })).rejects.toThrowError(options.generalError);
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'find')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when type's singular and unauthorized`, async () => {
-      const type = 'foo';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'find')]: false },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ type, namespace: 'some-ns' });
-      await expect(client.find(apiCallOptions)).rejects.toThrowError(options.forbiddenError);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'find')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'find',
-        [type],
-        [options.actions.savedObject.get(type, 'find')],
-        { options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when type's an array and unauthorized`, async () => {
-      const type1 = 'foo';
-      const type2 = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type1, 'find')]: false,
-          [options.actions.savedObject.get(type2, 'find')]: true,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ type: [type1, type2], namespace: 'some-ns' });
-      await expect(client.find(apiCallOptions)).rejects.toThrowError(options.forbiddenError);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [
-          options.actions.savedObject.get(type1, 'find'),
-          options.actions.savedObject.get(type2, 'find'),
-        ],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'find',
-        [type1, type2],
-        [options.actions.savedObject.get(type1, 'find')],
-        { options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.find when authorized`, async () => {
-      const type = 'foo';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'find')]: true },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.find.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ type, namespace: 'some-ns' });
-      await expect(client.find(apiCallOptions)).resolves.toBe(apiCallReturnValue);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'find')],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.find).toHaveBeenCalledWith(apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'find',
-        [type],
-        { options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#bulkGet', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.bulkGet([{ id: 'bar', type }])).rejects.toThrowError(
-        options.generalError
-      );
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'bulk_get')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type1 = 'foo';
-      const type2 = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type1, 'bulk_get')]: false,
-          [options.actions.savedObject.get(type2, 'bulk_get')]: true,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const objects = [
-        { type: type1, id: `bar-${type1}` },
-        { type: type2, id: `bar-${type2}` },
-      ];
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.bulkGet(objects, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [
-          options.actions.savedObject.get(type1, 'bulk_get'),
-          options.actions.savedObject.get(type2, 'bulk_get'),
-        ],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'bulk_get',
-        [type1, type2],
-        [options.actions.savedObject.get(type1, 'bulk_get')],
-        { objects, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.bulkGet when authorized`, async () => {
-      const type1 = 'foo';
-      const type2 = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type1, 'bulk_get')]: true,
-          [options.actions.savedObject.get(type2, 'bulk_get')]: true,
-        },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.bulkGet.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const objects = [
-        { type: type1, id: `id-${type1}` },
-        { type: type2, id: `id-${type2}` },
-      ];
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.bulkGet(objects, apiCallOptions)).resolves.toBe(apiCallReturnValue);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [
-          options.actions.savedObject.get(type1, 'bulk_get'),
-          options.actions.savedObject.get(type2, 'bulk_get'),
-        ],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.bulkGet).toHaveBeenCalledWith(objects, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'bulk_get',
-        [type1, type2],
-        { objects, options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#get', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.get(type, 'bar')).rejects.toThrowError(options.generalError);
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'get')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type = 'foo';
-      const id = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type, 'get')]: false,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.get(type, id, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'get')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'get',
-        [type],
-        [options.actions.savedObject.get(type, 'get')],
-        { type, id, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.get when authorized`, async () => {
-      const type = 'foo';
-      const id = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'get')]: true },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.get.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.get(type, id, apiCallOptions)).resolves.toBe(apiCallReturnValue);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'get')],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.get).toHaveBeenCalledWith(type, id, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'get',
-        [type],
-        { type, id, options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#update', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.update(type, 'bar', {})).rejects.toThrowError(options.generalError);
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'update')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type = 'foo';
-      const id = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type, 'update')]: false,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const attributes = { some: 'attr' };
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.update(type, id, attributes, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'update')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'update',
-        [type],
-        [options.actions.savedObject.get(type, 'update')],
-        { type, id, attributes, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.update when authorized`, async () => {
-      const type = 'foo';
-      const id = 'bar';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: { [options.actions.savedObject.get(type, 'update')]: true },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.update.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const attributes = { some: 'attr' };
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.update(type, id, attributes, apiCallOptions)).resolves.toBe(
-        apiCallReturnValue
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'update')],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.update).toHaveBeenCalledWith(type, id, attributes, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'update',
-        [type],
-        { type, id, attributes, options: apiCallOptions }
-      );
-    });
-  });
-
-  describe('#bulkUpdate', () => {
-    test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
-      const type = 'foo';
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(
-        new Error('An actual error would happen here')
-      );
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      await expect(client.bulkUpdate([{ id: 'bar', type, attributes: {} }])).rejects.toThrowError(
-        options.generalError
-      );
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'bulk_update')],
-        undefined
-      );
-      expect(options.errors.decorateGeneralError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`throws decorated ForbiddenError when unauthorized`, async () => {
-      const type = 'foo';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: false,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type, 'bulk_update')]: false,
-        },
-      });
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const objects = [{ type, id: `bar-${type}`, attributes: {} }];
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.bulkUpdate(objects, apiCallOptions)).rejects.toThrowError(
-        options.forbiddenError
-      );
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'bulk_update')],
-        apiCallOptions.namespace
-      );
-      expect(options.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
-        username,
-        'bulk_update',
-        [type],
-        [options.actions.savedObject.get(type, 'bulk_update')],
-        { objects, options: apiCallOptions }
-      );
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
-    });
-
-    test(`returns result of baseClient.bulkUpdate when authorized`, async () => {
-      const type = 'foo';
-      const username = Symbol();
-      const options = createSecureSavedObjectsClientWrapperOptions();
-      options.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({
-        hasAllRequested: true,
-        username,
-        privileges: {
-          [options.actions.savedObject.get(type, 'bulk_update')]: true,
-        },
-      });
-
-      const apiCallReturnValue = Symbol();
-      options.baseClient.bulkUpdate.mockReturnValue(apiCallReturnValue as any);
-
-      const client = new SecureSavedObjectsClientWrapper(options);
-
-      const objects = [{ type, id: `id-${type}`, attributes: {} }];
-      const apiCallOptions = Object.freeze({ namespace: 'some-ns' });
-      await expect(client.bulkUpdate(objects, apiCallOptions)).resolves.toBe(apiCallReturnValue);
-
-      expect(options.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
-        [options.actions.savedObject.get(type, 'bulk_update')],
-        apiCallOptions.namespace
-      );
-      expect(options.baseClient.bulkUpdate).toHaveBeenCalledWith(objects, apiCallOptions);
-      expect(options.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
-      expect(options.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
-        username,
-        'bulk_update',
-        [type],
-        { objects, options: apiCallOptions }
-      );
-    });
+describe('#delete', () => {
+  const type = 'foo';
+  const id = `${type}-id`;
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    await expectGeneralError(client.delete, { type, id });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    await expectForbiddenError(client.delete, { type, id, options });
+  });
+
+  test(`returns result of internalRepository.delete when authorized`, async () => {
+    const apiCallReturnValue = Symbol();
+    clientOpts.baseClient.delete.mockReturnValue(apiCallReturnValue as any);
+
+    const result = await expectSuccess(client.delete, { type, id, options });
+    expect(result).toBe(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    await expectPrivilegeCheck(client.delete, { type, id, options });
+  });
+});
+
+describe('#find', () => {
+  const type1 = 'foo';
+  const type2 = 'bar';
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    await expectGeneralError(client.find, { type: type1 });
+  });
+
+  test(`throws decorated ForbiddenError when type's singular and unauthorized`, async () => {
+    const options = Object.freeze({ type: type1, namespace: 'some-ns' });
+    await expectForbiddenError(client.find, { options });
+  });
+
+  test(`throws decorated ForbiddenError when type's an array and unauthorized`, async () => {
+    const options = Object.freeze({ type: [type1, type2], namespace: 'some-ns' });
+    await expectForbiddenError(client.find, { options });
+  });
+
+  test(`returns result of baseClient.find when authorized`, async () => {
+    const apiCallReturnValue = { saved_objects: [], foo: 'bar' };
+    clientOpts.baseClient.find.mockReturnValue(apiCallReturnValue as any);
+
+    const options = Object.freeze({ type: type1, namespace: 'some-ns' });
+    const result = await expectSuccess(client.find, { options });
+    expect(result).toEqual(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    const options = Object.freeze({ type: [type1, type2], namespace: 'some-ns' });
+    await expectPrivilegeCheck(client.find, { options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    const options = Object.freeze({ type: [type1, type2], namespace: 'some-ns' });
+    await expectObjectsNamespaceFiltering(client.find, { options });
+  });
+});
+
+describe('#get', () => {
+  const type = 'foo';
+  const id = `${type}-id`;
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    await expectGeneralError(client.get, { type, id });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    await expectForbiddenError(client.get, { type, id, options });
+  });
+
+  test(`returns result of baseClient.get when authorized`, async () => {
+    const apiCallReturnValue = Symbol();
+    clientOpts.baseClient.get.mockReturnValue(apiCallReturnValue as any);
+
+    const result = await expectSuccess(client.get, { type, id, options });
+    expect(result).toBe(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    await expectPrivilegeCheck(client.get, { type, id, options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    await expectObjectNamespaceFiltering(client.get, { type, id, options });
+  });
+});
+
+describe('#deleteFromNamespaces', () => {
+  const type = 'foo';
+  const id = `${type}-id`;
+  const namespace1 = 'foo-namespace';
+  const namespace2 = 'bar-namespace';
+  const namespaces = [namespace1, namespace2];
+  const privilege = `mock-saved_object:${type}/delete`;
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    await expectGeneralError(client.deleteFromNamespaces, { type, id, namespaces });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+      getMockCheckPrivilegesFailure
+    );
+
+    await expect(client.deleteFromNamespaces(type, id, namespaces)).rejects.toThrowError(
+      clientOpts.forbiddenError
+    );
+
+    expect(clientOpts.errors.decorateForbiddenError).toHaveBeenCalledTimes(1);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledTimes(1);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).toHaveBeenCalledWith(
+      USERNAME,
+      'deleteFromNamespaces', // action for privilege check is 'delete', but auditAction is 'deleteFromNamespaces'
+      [type],
+      namespaces.sort(),
+      [{ privilege, spaceId: namespace1 }],
+      { type, id, namespaces, options: {} }
+    );
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).not.toHaveBeenCalled();
+  });
+
+  test(`returns result of baseClient.deleteFromNamespaces when authorized`, async () => {
+    const apiCallReturnValue = Symbol();
+    clientOpts.baseClient.deleteFromNamespaces.mockReturnValue(apiCallReturnValue as any);
+
+    const result = await client.deleteFromNamespaces(type, id, namespaces);
+    expect(result).toBe(apiCallReturnValue);
+
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationFailure).not.toHaveBeenCalled();
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledTimes(1);
+    expect(clientOpts.auditLogger.savedObjectsAuthorizationSuccess).toHaveBeenCalledWith(
+      USERNAME,
+      'deleteFromNamespaces', // action for privilege check is 'delete', but auditAction is 'deleteFromNamespaces'
+      [type],
+      namespaces.sort(),
+      { type, id, namespaces, options: {} }
+    );
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation(
+      getMockCheckPrivilegesFailure
+    );
+
+    await expect(client.deleteFromNamespaces(type, id, namespaces)).rejects.toThrow(); // test is simpler with error case
+
+    expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledTimes(1);
+    expect(clientOpts.checkSavedObjectsPrivilegesAsCurrentUser).toHaveBeenCalledWith(
+      [privilege],
+      namespaces
+    );
+  });
+});
+
+describe('#update', () => {
+  const type = 'foo';
+  const id = `${type}-id`;
+  const attributes = { some: 'attr' };
+  const options = Object.freeze({ namespace: 'some-ns' });
+
+  test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
+    await expectGeneralError(client.update, { type, id, attributes });
+  });
+
+  test(`throws decorated ForbiddenError when unauthorized`, async () => {
+    await expectForbiddenError(client.update, { type, id, attributes, options });
+  });
+
+  test(`returns result of baseClient.update when authorized`, async () => {
+    const apiCallReturnValue = Symbol();
+    clientOpts.baseClient.update.mockReturnValue(apiCallReturnValue as any);
+
+    const result = await expectSuccess(client.update, { type, id, attributes, options });
+    expect(result).toBe(apiCallReturnValue);
+  });
+
+  test(`checks privileges for user, actions, and namespace`, async () => {
+    await expectPrivilegeCheck(client.update, { type, id, attributes, options });
+  });
+
+  test(`filters namespaces that the user doesn't have access to`, async () => {
+    await expectObjectNamespaceFiltering(client.update, { type, id, attributes, options });
+  });
+});
+
+describe('other', () => {
+  test(`assigns errors from constructor to .errors`, () => {
+    expect(client.errors).toBe(clientOpts.errors);
   });
 });
diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
index 2209e7fb66fcb..29503d475be73 100644
--- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
+++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
@@ -13,9 +13,13 @@ import {
   SavedObjectsCreateOptions,
   SavedObjectsFindOptions,
   SavedObjectsUpdateOptions,
+  SavedObjectsAddToNamespacesOptions,
+  SavedObjectsDeleteFromNamespacesOptions,
 } from '../../../../../src/core/server';
 import { SecurityAuditLogger } from '../audit';
 import { Actions, CheckSavedObjectsPrivileges } from '../authorization';
+import { CheckPrivilegesResponse } from '../authorization/check_privileges';
+import { SpacesService } from '../plugin';
 
 interface SecureSavedObjectsClientWrapperOptions {
   actions: Actions;
@@ -23,6 +27,19 @@ interface SecureSavedObjectsClientWrapperOptions {
   baseClient: SavedObjectsClientContract;
   errors: SavedObjectsClientContract['errors'];
   checkSavedObjectsPrivilegesAsCurrentUser: CheckSavedObjectsPrivileges;
+  getSpacesService(): SpacesService | undefined;
+}
+
+interface SavedObjectNamespaces {
+  namespaces?: string[];
+}
+
+interface SavedObjectsNamespaces {
+  saved_objects: SavedObjectNamespaces[];
+}
+
+function uniq<T>(arr: T[]): T[] {
+  return Array.from(new Set<T>(arr));
 }
 
 export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContract {
@@ -30,19 +47,23 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
   private readonly auditLogger: PublicMethodsOf<SecurityAuditLogger>;
   private readonly baseClient: SavedObjectsClientContract;
   private readonly checkSavedObjectsPrivilegesAsCurrentUser: CheckSavedObjectsPrivileges;
+  private getSpacesService: () => SpacesService | undefined;
   public readonly errors: SavedObjectsClientContract['errors'];
+
   constructor({
     actions,
     auditLogger,
     baseClient,
     checkSavedObjectsPrivilegesAsCurrentUser,
     errors,
+    getSpacesService,
   }: SecureSavedObjectsClientWrapperOptions) {
     this.errors = errors;
     this.actions = actions;
     this.auditLogger = auditLogger;
     this.baseClient = baseClient;
     this.checkSavedObjectsPrivilegesAsCurrentUser = checkSavedObjectsPrivilegesAsCurrentUser;
+    this.getSpacesService = getSpacesService;
   }
 
   public async create<T = unknown>(
@@ -52,7 +73,8 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
   ) {
     await this.ensureAuthorized(type, 'create', options.namespace, { type, attributes, options });
 
-    return await this.baseClient.create(type, attributes, options);
+    const savedObject = await this.baseClient.create(type, attributes, options);
+    return await this.redactSavedObjectNamespaces(savedObject);
   }
 
   public async bulkCreate<T = unknown>(
@@ -66,7 +88,8 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
       { objects, options }
     );
 
-    return await this.baseClient.bulkCreate(objects, options);
+    const response = await this.baseClient.bulkCreate(objects, options);
+    return await this.redactSavedObjectsNamespaces(response);
   }
 
   public async delete(type: string, id: string, options: SavedObjectsBaseOptions = {}) {
@@ -78,7 +101,8 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
   public async find<T = unknown>(options: SavedObjectsFindOptions) {
     await this.ensureAuthorized(options.type, 'find', options.namespace, { options });
 
-    return this.baseClient.find<T>(options);
+    const response = await this.baseClient.find<T>(options);
+    return await this.redactSavedObjectsNamespaces(response);
   }
 
   public async bulkGet<T = unknown>(
@@ -90,13 +114,15 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
       options,
     });
 
-    return await this.baseClient.bulkGet<T>(objects, options);
+    const response = await this.baseClient.bulkGet<T>(objects, options);
+    return await this.redactSavedObjectsNamespaces(response);
   }
 
   public async get<T = unknown>(type: string, id: string, options: SavedObjectsBaseOptions = {}) {
     await this.ensureAuthorized(type, 'get', options.namespace, { type, id, options });
 
-    return await this.baseClient.get<T>(type, id, options);
+    const savedObject = await this.baseClient.get<T>(type, id, options);
+    return await this.redactSavedObjectNamespaces(savedObject);
   }
 
   public async update<T = unknown>(
@@ -105,14 +131,44 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
     attributes: Partial<T>,
     options: SavedObjectsUpdateOptions = {}
   ) {
-    await this.ensureAuthorized(type, 'update', options.namespace, {
-      type,
-      id,
-      attributes,
-      options,
-    });
+    const args = { type, id, attributes, options };
+    await this.ensureAuthorized(type, 'update', options.namespace, args);
 
-    return await this.baseClient.update(type, id, attributes, options);
+    const savedObject = await this.baseClient.update(type, id, attributes, options);
+    return await this.redactSavedObjectNamespaces(savedObject);
+  }
+
+  public async addToNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsAddToNamespacesOptions = {}
+  ) {
+    const args = { type, id, namespaces, options };
+    const { namespace } = options;
+    // To share an object, the user must have the "create" permission in each of the destination namespaces.
+    await this.ensureAuthorized(type, 'create', namespaces, args, 'addToNamespacesCreate');
+
+    // To share an object, the user must also have the "update" permission in one or more of the source namespaces. Because the
+    // `addToNamespaces` operation is scoped to the current namespace, we can just check if the user has the "update" permission in the
+    // current namespace. If the user has permission, but the saved object doesn't exist in this namespace, the base client operation will
+    // result in a 404 error.
+    await this.ensureAuthorized(type, 'update', namespace, args, 'addToNamespacesUpdate');
+
+    return await this.baseClient.addToNamespaces(type, id, namespaces, options);
+  }
+
+  public async deleteFromNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsDeleteFromNamespacesOptions = {}
+  ) {
+    const args = { type, id, namespaces, options };
+    // To un-share an object, the user must have the "delete" permission in each of the target namespaces.
+    await this.ensureAuthorized(type, 'delete', namespaces, args, 'deleteFromNamespaces');
+
+    return await this.baseClient.deleteFromNamespaces(type, id, namespaces, options);
   }
 
   public async bulkUpdate<T = unknown>(
@@ -126,12 +182,16 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
       { objects, options }
     );
 
-    return await this.baseClient.bulkUpdate<T>(objects, options);
+    const response = await this.baseClient.bulkUpdate<T>(objects, options);
+    return await this.redactSavedObjectsNamespaces(response);
   }
 
-  private async checkPrivileges(actions: string | string[], namespace?: string) {
+  private async checkPrivileges(
+    actions: string | string[],
+    namespaceOrNamespaces?: string | string[]
+  ) {
     try {
-      return await this.checkSavedObjectsPrivilegesAsCurrentUser(actions, namespace);
+      return await this.checkSavedObjectsPrivilegesAsCurrentUser(actions, namespaceOrNamespaces);
     } catch (error) {
       throw this.errors.decorateGeneralError(error, error.body && error.body.reason);
     }
@@ -140,43 +200,133 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
   private async ensureAuthorized(
     typeOrTypes: string | string[],
     action: string,
-    namespace?: string,
-    args?: Record<string, unknown>
+    namespaceOrNamespaces?: string | string[],
+    args?: Record<string, unknown>,
+    auditAction: string = action,
+    requiresAll = true
   ) {
     const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
     const actionsToTypesMap = new Map(
       types.map(type => [this.actions.savedObject.get(type, action), type])
     );
     const actions = Array.from(actionsToTypesMap.keys());
-    const { hasAllRequested, username, privileges } = await this.checkPrivileges(
-      actions,
-      namespace
-    );
+    const result = await this.checkPrivileges(actions, namespaceOrNamespaces);
+
+    const { hasAllRequested, username, privileges } = result;
+    const spaceIds = uniq(
+      privileges.map(({ resource }) => resource).filter(x => x !== undefined)
+    ).sort() as string[];
 
-    if (hasAllRequested) {
-      this.auditLogger.savedObjectsAuthorizationSuccess(username, action, types, args);
+    const isAuthorized =
+      (requiresAll && hasAllRequested) ||
+      (!requiresAll && privileges.some(({ authorized }) => authorized));
+    if (isAuthorized) {
+      this.auditLogger.savedObjectsAuthorizationSuccess(
+        username,
+        auditAction,
+        types,
+        spaceIds,
+        args
+      );
     } else {
       const missingPrivileges = this.getMissingPrivileges(privileges);
       this.auditLogger.savedObjectsAuthorizationFailure(
         username,
-        action,
+        auditAction,
         types,
+        spaceIds,
         missingPrivileges,
         args
       );
-      const msg = `Unable to ${action} ${missingPrivileges
-        .map(privilege => actionsToTypesMap.get(privilege))
-        .sort()
-        .join(',')}`;
+      const targetTypes = uniq(
+        missingPrivileges.map(({ privilege }) => actionsToTypesMap.get(privilege)).sort()
+      ).join(',');
+      const msg = `Unable to ${action} ${targetTypes}`;
       throw this.errors.decorateForbiddenError(new Error(msg));
     }
   }
 
-  private getMissingPrivileges(privileges: Record<string, boolean>) {
-    return Object.keys(privileges).filter(privilege => !privileges[privilege]);
+  private getMissingPrivileges(privileges: CheckPrivilegesResponse['privileges']) {
+    return privileges
+      .filter(({ authorized }) => !authorized)
+      .map(({ resource, privilege }) => ({ spaceId: resource, privilege }));
   }
 
   private getUniqueObjectTypes(objects: Array<{ type: string }>) {
-    return [...new Set(objects.map(o => o.type))];
+    return uniq(objects.map(o => o.type));
+  }
+
+  private async getNamespacesPrivilegeMap(namespaces: string[]) {
+    const action = this.actions.login;
+    const checkPrivilegesResult = await this.checkPrivileges(action, namespaces);
+    // check if the user can log into each namespace
+    const map = checkPrivilegesResult.privileges.reduce(
+      (acc: Record<string, boolean>, { resource, authorized }) => {
+        // there should never be a case where more than one privilege is returned for a given space
+        // if there is, fail-safe (authorized + unauthorized = unauthorized)
+        if (resource && (!authorized || !acc.hasOwnProperty(resource))) {
+          acc[resource] = authorized;
+        }
+        return acc;
+      },
+      {}
+    );
+    return map;
+  }
+
+  private redactAndSortNamespaces(spaceIds: string[], privilegeMap: Record<string, boolean>) {
+    const comparator = (a: string, b: string) => {
+      const _a = a.toLowerCase();
+      const _b = b.toLowerCase();
+      if (_a === '?') {
+        return 1;
+      } else if (_a < _b) {
+        return -1;
+      } else if (_a > _b) {
+        return 1;
+      }
+      return 0;
+    };
+    return spaceIds.map(spaceId => (privilegeMap[spaceId] ? spaceId : '?')).sort(comparator);
+  }
+
+  private async redactSavedObjectNamespaces<T extends SavedObjectNamespaces>(
+    savedObject: T
+  ): Promise<T> {
+    if (this.getSpacesService() === undefined || savedObject.namespaces == null) {
+      return savedObject;
+    }
+
+    const privilegeMap = await this.getNamespacesPrivilegeMap(savedObject.namespaces);
+
+    return {
+      ...savedObject,
+      namespaces: this.redactAndSortNamespaces(savedObject.namespaces, privilegeMap),
+    };
+  }
+
+  private async redactSavedObjectsNamespaces<T extends SavedObjectsNamespaces>(
+    response: T
+  ): Promise<T> {
+    if (this.getSpacesService() === undefined) {
+      return response;
+    }
+    const { saved_objects: savedObjects } = response;
+    const namespaces = uniq(savedObjects.flatMap(savedObject => savedObject.namespaces || []));
+    if (namespaces.length === 0) {
+      return response;
+    }
+
+    const privilegeMap = await this.getNamespacesPrivilegeMap(namespaces);
+
+    return {
+      ...response,
+      saved_objects: savedObjects.map(savedObject => ({
+        ...savedObject,
+        namespaces:
+          savedObject.namespaces &&
+          this.redactAndSortNamespaces(savedObject.namespaces, privilegeMap),
+      })),
+    };
   }
 }
diff --git a/x-pack/plugins/spaces/public/management/edit_space/delete_spaces_button.tsx b/x-pack/plugins/spaces/public/management/edit_space/delete_spaces_button.tsx
index 28e45bc8cfd2a..ea63905e27b26 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/delete_spaces_button.tsx
+++ b/x-pack/plugins/spaces/public/management/edit_space/delete_spaces_button.tsx
@@ -99,10 +99,14 @@ export class DeleteSpacesButton extends Component<Props, State> {
   public deleteSpaces = async () => {
     const { spacesManager, space } = this.props;
 
+    this.setState({
+      showConfirmDeleteModal: false,
+    });
+
     try {
       await spacesManager.deleteSpace(space);
     } catch (error) {
-      const { message: errorMessage = '' } = error.data || {};
+      const { message: errorMessage = '' } = error.data || error.body || {};
 
       this.props.notifications.toasts.addDanger(
         i18n.translate('xpack.spaces.management.deleteSpacesButton.deleteSpaceErrorTitle', {
@@ -110,12 +114,9 @@ export class DeleteSpacesButton extends Component<Props, State> {
           values: { errorMessage },
         })
       );
+      return;
     }
 
-    this.setState({
-      showConfirmDeleteModal: false,
-    });
-
     const message = i18n.translate(
       'xpack.spaces.management.deleteSpacesButton.spaceSuccessfullyDeletedNotificationMessage',
       {
diff --git a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx
index ff4be84207832..df5e6a2ca34af 100644
--- a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx
+++ b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx
@@ -176,10 +176,14 @@ export class SpacesGridPage extends Component<Props, State> {
       return;
     }
 
+    this.setState({
+      showConfirmDeleteModal: false,
+    });
+
     try {
       await spacesManager.deleteSpace(space);
     } catch (error) {
-      const { message: errorMessage = '' } = error.data || {};
+      const { message: errorMessage = '' } = error.data || error.body || {};
 
       this.props.notifications.toasts.addDanger(
         i18n.translate('xpack.spaces.management.spacesGridPage.errorDeletingSpaceErrorMessage', {
@@ -189,12 +193,9 @@ export class SpacesGridPage extends Component<Props, State> {
           },
         })
       );
+      return;
     }
 
-    this.setState({
-      showConfirmDeleteModal: false,
-    });
-
     this.loadGrid();
 
     const message = i18n.translate(
diff --git a/x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts
index 59e157c3fc2db..72faab0d2c892 100644
--- a/x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts
+++ b/x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts
@@ -188,11 +188,13 @@ describe('copySavedObjectsToSpaces', () => {
               },
             ],
             "savedObjectsClient": Object {
+              "addToNamespaces": [MockFunction],
               "bulkCreate": [MockFunction],
               "bulkGet": [MockFunction],
               "bulkUpdate": [MockFunction],
               "create": [MockFunction],
               "delete": [MockFunction],
+              "deleteFromNamespaces": [MockFunction],
               "errors": [Function],
               "find": [MockFunction],
               "get": [MockFunction],
@@ -252,11 +254,13 @@ describe('copySavedObjectsToSpaces', () => {
               "readable": false,
             },
             "savedObjectsClient": Object {
+              "addToNamespaces": [MockFunction],
               "bulkCreate": [MockFunction],
               "bulkGet": [MockFunction],
               "bulkUpdate": [MockFunction],
               "create": [MockFunction],
               "delete": [MockFunction],
+              "deleteFromNamespaces": [MockFunction],
               "errors": [Function],
               "find": [MockFunction],
               "get": [MockFunction],
@@ -315,11 +319,13 @@ describe('copySavedObjectsToSpaces', () => {
               "readable": false,
             },
             "savedObjectsClient": Object {
+              "addToNamespaces": [MockFunction],
               "bulkCreate": [MockFunction],
               "bulkGet": [MockFunction],
               "bulkUpdate": [MockFunction],
               "create": [MockFunction],
               "delete": [MockFunction],
+              "deleteFromNamespaces": [MockFunction],
               "errors": [Function],
               "find": [MockFunction],
               "get": [MockFunction],
diff --git a/x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts
index 7809f1f8be66f..aa1d5e9a47832 100644
--- a/x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts
+++ b/x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts
@@ -204,11 +204,13 @@ describe('resolveCopySavedObjectsToSpacesConflicts', () => {
               },
             ],
             "savedObjectsClient": Object {
+              "addToNamespaces": [MockFunction],
               "bulkCreate": [MockFunction],
               "bulkGet": [MockFunction],
               "bulkUpdate": [MockFunction],
               "create": [MockFunction],
               "delete": [MockFunction],
+              "deleteFromNamespaces": [MockFunction],
               "errors": [Function],
               "find": [MockFunction],
               "get": [MockFunction],
@@ -275,11 +277,13 @@ describe('resolveCopySavedObjectsToSpacesConflicts', () => {
               },
             ],
             "savedObjectsClient": Object {
+              "addToNamespaces": [MockFunction],
               "bulkCreate": [MockFunction],
               "bulkGet": [MockFunction],
               "bulkUpdate": [MockFunction],
               "create": [MockFunction],
               "delete": [MockFunction],
+              "deleteFromNamespaces": [MockFunction],
               "errors": [Function],
               "find": [MockFunction],
               "get": [MockFunction],
@@ -345,11 +349,13 @@ describe('resolveCopySavedObjectsToSpacesConflicts', () => {
               },
             ],
             "savedObjectsClient": Object {
+              "addToNamespaces": [MockFunction],
               "bulkCreate": [MockFunction],
               "bulkGet": [MockFunction],
               "bulkUpdate": [MockFunction],
               "create": [MockFunction],
               "delete": [MockFunction],
+              "deleteFromNamespaces": [MockFunction],
               "errors": [Function],
               "find": [MockFunction],
               "get": [MockFunction],
diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts
index 74e75fb8f12c7..c83830f6feace 100644
--- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts
+++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts
@@ -250,14 +250,10 @@ describe('#getAll', () => {
           mockAuthorization.mode.useRbacForRequest.mockReturnValue(true);
           mockCheckPrivilegesAtSpaces.mockReturnValue({
             username,
-            spacePrivileges: {
-              [savedObjects[0].id]: {
-                [privilege]: false,
-              },
-              [savedObjects[1].id]: {
-                [privilege]: false,
-              },
-            },
+            privileges: [
+              { resource: savedObjects[0].id, privilege, authorized: false },
+              { resource: savedObjects[1].id, privilege, authorized: false },
+            ],
           });
           const maxSpaces = 1234;
           const mockConfig = createMockConfig({
@@ -314,14 +310,10 @@ describe('#getAll', () => {
           mockAuthorization.mode.useRbacForRequest.mockReturnValue(true);
           mockCheckPrivilegesAtSpaces.mockReturnValue({
             username,
-            spacePrivileges: {
-              [savedObjects[0].id]: {
-                [privilege]: true,
-              },
-              [savedObjects[1].id]: {
-                [privilege]: false,
-              },
-            },
+            privileges: [
+              { resource: savedObjects[0].id, privilege, authorized: true },
+              { resource: savedObjects[1].id, privilege, authorized: false },
+            ],
           });
           const mockInternalRepository = {
             find: jest.fn().mockReturnValue({
diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts
index 22c34c03368e3..0c066fb76994f 100644
--- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts
+++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts
@@ -74,16 +74,14 @@ export class SpacesClient {
 
       const privilege = privilegeFactory(this.authorization!);
 
-      const { username, spacePrivileges } = await checkPrivileges.atSpaces(spaceIds, privilege);
+      const { username, privileges } = await checkPrivileges.atSpaces(spaceIds, privilege);
 
-      const authorized = Object.keys(spacePrivileges).filter(spaceId => {
-        return spacePrivileges[spaceId][privilege];
-      });
+      const authorized = privileges.filter(x => x.authorized).map(x => x.resource);
 
       this.debugLogger(
         `SpacesClient.getAll(), authorized for ${
           authorized.length
-        } spaces, derived from ES privilege check: ${JSON.stringify(spacePrivileges)}`
+        } spaces, derived from ES privilege check: ${JSON.stringify(privileges)}`
       );
 
       if (authorized.length === 0) {
@@ -94,7 +92,7 @@ export class SpacesClient {
         throw Boom.forbidden();
       }
 
-      this.auditLogger.spacesAuthorizationSuccess(username, 'getAll', authorized);
+      this.auditLogger.spacesAuthorizationSuccess(username, 'getAll', authorized as string[]);
       const filteredSpaces: Space[] = spaces.filter((space: any) => authorized.includes(space.id));
       this.debugLogger(
         `SpacesClient.getAll(), using RBAC. returning spaces: ${filteredSpaces
@@ -211,9 +209,9 @@ export class SpacesClient {
       throw Boom.badRequest('This Space cannot be deleted because it is reserved.');
     }
 
-    await repository.delete('space', id);
-
     await repository.deleteByNamespace(id);
+
+    await repository.delete('space', id);
   }
 
   private useRbac(): boolean {
diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts
index f2ba8785f5a3f..511e9676940d2 100644
--- a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts
+++ b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts
@@ -11,7 +11,13 @@ import {
   mockRouteContext,
   mockRouteContextWithInvalidLicense,
 } from '../__fixtures__';
-import { CoreSetup, IRouter, kibanaResponseFactory, RouteValidatorConfig } from 'src/core/server';
+import {
+  CoreSetup,
+  IRouter,
+  kibanaResponseFactory,
+  RouteValidatorConfig,
+  SavedObjectsErrorHelpers,
+} from 'src/core/server';
 import {
   loggingServiceMock,
   httpServiceMock,
@@ -75,6 +81,7 @@ describe('Spaces Public API', () => {
     return {
       routeValidation: routeDefinition.validate as RouteValidatorConfig<{}, {}, {}>,
       routeHandler,
+      savedObjectsRepositoryMock,
     };
   };
 
@@ -143,6 +150,27 @@ describe('Spaces Public API', () => {
     expect(status).toEqual(404);
   });
 
+  it(`returns http/400 when scripts cannot be executed in Elasticsearch`, async () => {
+    const { routeHandler, savedObjectsRepositoryMock } = await setup();
+
+    const request = httpServerMock.createKibanaRequest({
+      params: {
+        id: 'a-space',
+      },
+      method: 'delete',
+    });
+    // @ts-ignore
+    savedObjectsRepositoryMock.deleteByNamespace.mockRejectedValue(
+      SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError(new Error())
+    );
+    const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);
+
+    const { status, payload } = response;
+
+    expect(status).toEqual(400);
+    expect(payload.message).toEqual('Cannot execute script in Elasticsearch query');
+  });
+
   it(`DELETE spaces/{id}' cannot delete reserved spaces`, async () => {
     const { routeHandler } = await setup();
 
diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts
index 4b7e6b00182ac..150f1d198cdf6 100644
--- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts
+++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts
@@ -4,6 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+import Boom from 'boom';
 import { schema } from '@kbn/config-schema';
 import { SavedObjectsErrorHelpers } from '../../../../../../../src/core/server';
 import { wrapError } from '../../../lib/errors';
@@ -12,7 +13,7 @@ import { ExternalRouteDeps } from '.';
 import { createLicensedRouteHandler } from '../../lib';
 
 export function initDeleteSpacesApi(deps: ExternalRouteDeps) {
-  const { externalRouter, spacesService } = deps;
+  const { externalRouter, log, spacesService } = deps;
 
   externalRouter.delete(
     {
@@ -33,6 +34,13 @@ export function initDeleteSpacesApi(deps: ExternalRouteDeps) {
       } catch (error) {
         if (SavedObjectsErrorHelpers.isNotFoundError(error)) {
           return response.notFound();
+        } else if (SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)) {
+          log.error(
+            `Failed to delete space '${id}', cannot execute script in Elasticsearch query: ${error.message}`
+          );
+          return response.customError(
+            wrapError(Boom.badRequest('Cannot execute script in Elasticsearch query'))
+          );
         }
         return response.customError(wrapError(error));
       }
diff --git a/x-pack/plugins/spaces/server/routes/api/external/index.ts b/x-pack/plugins/spaces/server/routes/api/external/index.ts
index 1bdb7ceb8a3f7..079f690bfe546 100644
--- a/x-pack/plugins/spaces/server/routes/api/external/index.ts
+++ b/x-pack/plugins/spaces/server/routes/api/external/index.ts
@@ -12,6 +12,8 @@ import { initPostSpacesApi } from './post';
 import { initPutSpacesApi } from './put';
 import { SpacesServiceSetup } from '../../../spaces_service/spaces_service';
 import { initCopyToSpacesApi } from './copy_to_space';
+import { initShareAddSpacesApi } from './share_add_spaces';
+import { initShareRemoveSpacesApi } from './share_remove_spaces';
 
 export interface ExternalRouteDeps {
   externalRouter: IRouter;
@@ -28,4 +30,6 @@ export function initExternalSpacesApi(deps: ExternalRouteDeps) {
   initPostSpacesApi(deps);
   initPutSpacesApi(deps);
   initCopyToSpacesApi(deps);
+  initShareAddSpacesApi(deps);
+  initShareRemoveSpacesApi(deps);
 }
diff --git a/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts b/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts
new file mode 100644
index 0000000000000..f40cc5cc50572
--- /dev/null
+++ b/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { wrapError } from '../../../lib/errors';
+import { ExternalRouteDeps } from '.';
+import { SPACE_ID_REGEX } from '../../../lib/space_schema';
+import { createLicensedRouteHandler } from '../../lib';
+
+const uniq = <T>(arr: T[]): T[] => Array.from(new Set<T>(arr));
+export function initShareAddSpacesApi(deps: ExternalRouteDeps) {
+  const { externalRouter, getStartServices } = deps;
+
+  externalRouter.post(
+    {
+      path: '/api/spaces/_share_saved_object_add',
+      validate: {
+        body: schema.object({
+          spaces: schema.arrayOf(
+            schema.string({
+              validate: value => {
+                if (!SPACE_ID_REGEX.test(value)) {
+                  return `lower case, a-z, 0-9, "_", and "-" are allowed`;
+                }
+              },
+            }),
+            {
+              validate: spaceIds => {
+                if (!spaceIds.length) {
+                  return 'must specify one or more space ids';
+                } else if (uniq(spaceIds).length !== spaceIds.length) {
+                  return 'duplicate space ids are not allowed';
+                }
+              },
+            }
+          ),
+          object: schema.object({
+            type: schema.string(),
+            id: schema.string(),
+          }),
+        }),
+      },
+    },
+    createLicensedRouteHandler(async (_context, request, response) => {
+      const [startServices] = await getStartServices();
+      const scopedClient = startServices.savedObjects.getScopedClient(request);
+
+      const spaces = request.body.spaces;
+      const { type, id } = request.body.object;
+
+      try {
+        await scopedClient.addToNamespaces(type, id, spaces);
+      } catch (error) {
+        return response.customError(wrapError(error));
+      }
+      return response.noContent();
+    })
+  );
+}
diff --git a/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts b/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts
new file mode 100644
index 0000000000000..5f58a5dfd5e5f
--- /dev/null
+++ b/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { schema } from '@kbn/config-schema';
+import { wrapError } from '../../../lib/errors';
+import { ExternalRouteDeps } from '.';
+import { SPACE_ID_REGEX } from '../../../lib/space_schema';
+import { createLicensedRouteHandler } from '../../lib';
+
+const uniq = <T>(arr: T[]): T[] => Array.from(new Set<T>(arr));
+export function initShareRemoveSpacesApi(deps: ExternalRouteDeps) {
+  const { externalRouter, getStartServices } = deps;
+
+  externalRouter.post(
+    {
+      path: '/api/spaces/_share_saved_object_remove',
+      validate: {
+        body: schema.object({
+          spaces: schema.arrayOf(
+            schema.string({
+              validate: value => {
+                if (!SPACE_ID_REGEX.test(value)) {
+                  return `lower case, a-z, 0-9, "_", and "-" are allowed`;
+                }
+              },
+            }),
+            {
+              validate: spaceIds => {
+                if (!spaceIds.length) {
+                  return 'must specify one or more space ids';
+                } else if (uniq(spaceIds).length !== spaceIds.length) {
+                  return 'duplicate space ids are not allowed';
+                }
+              },
+            }
+          ),
+          object: schema.object({
+            type: schema.string(),
+            id: schema.string(),
+          }),
+        }),
+      },
+    },
+    createLicensedRouteHandler(async (_context, request, response) => {
+      const [startServices] = await getStartServices();
+      const scopedClient = startServices.savedObjects.getScopedClient(request);
+
+      const spaces = request.body.spaces;
+      const { type, id } = request.body.object;
+
+      try {
+        await scopedClient.deleteFromNamespaces(type, id, spaces);
+      } catch (error) {
+        return response.customError(wrapError(error));
+      }
+      return response.noContent();
+    })
+  );
+}
diff --git a/x-pack/plugins/spaces/server/saved_objects/__snapshots__/spaces_saved_objects_client.test.ts.snap b/x-pack/plugins/spaces/server/saved_objects/__snapshots__/spaces_saved_objects_client.test.ts.snap
deleted file mode 100644
index 8b1a258138355..0000000000000
--- a/x-pack/plugins/spaces/server/saved_objects/__snapshots__/spaces_saved_objects_client.test.ts.snap
+++ /dev/null
@@ -1,29 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`default space #bulkCreate throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`default space #bulkGet throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`default space #create throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`default space #delete throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`default space #find throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`default space #get throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`default space #update throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #bulkCreate throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #bulkGet throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #create throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #delete throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #find throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #get throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
-
-exports[`space_1 space #update throws error if options.namespace is specified 1`] = `"Spaces currently determines the namespaces"`;
diff --git a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts
index 2d6fe36792c40..f9961329c088b 100644
--- a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts
+++ b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts
@@ -50,42 +50,41 @@ const createMockResponse = () => ({
   references: [],
 });
 
+const ERROR_NAMESPACE_SPECIFIED = 'Spaces currently determines the namespaces';
+
 [
   { id: DEFAULT_SPACE_ID, expectedNamespace: undefined },
   { id: 'space_1', expectedNamespace: 'space_1' },
 ].forEach(currentSpace => {
   describe(`${currentSpace.id} space`, () => {
+    const createSpacesSavedObjectsClient = async () => {
+      const request = createMockRequest();
+      const baseClient = createMockClient();
+      const spacesService = await createSpacesService(currentSpace.id);
+
+      const client = new SpacesSavedObjectsClient({
+        request,
+        baseClient,
+        spacesService,
+        typeRegistry,
+      });
+      return { client, baseClient };
+    };
+
     describe('#get', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
-        await expect(
-          client.get('foo', '', { namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        await expect(client.get('foo', '', { namespace: 'bar' })).rejects.toThrow(
+          ERROR_NAMESPACE_SPECIFIED
+        );
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
         const expectedReturnValue = createMockResponse();
         baseClient.get.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
 
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
         const type = Symbol();
         const id = Symbol();
         const options = Object.freeze({ foo: 'bar' });
@@ -102,37 +101,17 @@ const createMockResponse = () => ({
 
     describe('#bulkGet', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
         await expect(
           client.bulkGet([{ id: '', type: 'foo' }], { namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const expectedReturnValue = {
-          saved_objects: [createMockResponse()],
-        };
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
+        const expectedReturnValue = { saved_objects: [createMockResponse()] };
         baseClient.bulkGet.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
 
         const objects = [{ type: 'foo' }];
         const options = Object.freeze({ foo: 'bar' });
@@ -149,25 +128,15 @@ const createMockResponse = () => ({
 
     describe('#find', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
-        await expect(
-          client.find({ type: 'foo', namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        await expect(client.find({ type: 'foo', namespace: 'bar' })).rejects.toThrow(
+          ERROR_NAMESPACE_SPECIFIED
+        );
       });
 
       test(`passes options.type to baseClient if valid singular type specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
         const expectedReturnValue = {
           saved_objects: [createMockResponse()],
           total: 1,
@@ -175,16 +144,8 @@ const createMockResponse = () => ({
           page: 0,
         };
         baseClient.find.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
 
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
         const options = Object.freeze({ type: 'foo' });
-
         const actualReturnValue = await client.find(options);
 
         expect(actualReturnValue).toBe(expectedReturnValue);
@@ -194,9 +155,8 @@ const createMockResponse = () => ({
         });
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
         const expectedReturnValue = {
           saved_objects: [createMockResponse()],
           total: 1,
@@ -204,14 +164,6 @@ const createMockResponse = () => ({
           page: 0,
         };
         baseClient.find.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
 
         const options = Object.freeze({ type: ['foo', 'bar'] });
         const actualReturnValue = await client.find(options);
@@ -226,35 +178,17 @@ const createMockResponse = () => ({
 
     describe('#create', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
-        await expect(
-          client.create('foo', {}, { namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        await expect(client.create('foo', {}, { namespace: 'bar' })).rejects.toThrow(
+          ERROR_NAMESPACE_SPECIFIED
+        );
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
         const expectedReturnValue = createMockResponse();
         baseClient.create.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
 
         const type = Symbol();
         const attributes = Symbol();
@@ -272,37 +206,17 @@ const createMockResponse = () => ({
 
     describe('#bulkCreate', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
         await expect(
           client.bulkCreate([{ id: '', type: 'foo', attributes: {} }], { namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const expectedReturnValue = {
-          saved_objects: [createMockResponse()],
-        };
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
+        const expectedReturnValue = { saved_objects: [createMockResponse()] };
         baseClient.bulkCreate.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
 
         const objects = [{ type: 'foo' }];
         const options = Object.freeze({ foo: 'bar' });
@@ -319,36 +233,18 @@ const createMockResponse = () => ({
 
     describe('#update', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
         await expect(
           // @ts-ignore
           client.update(null, null, null, { namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
         const expectedReturnValue = createMockResponse();
         baseClient.update.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
 
         const type = Symbol();
         const id = Symbol();
@@ -366,21 +262,19 @@ const createMockResponse = () => ({
     });
 
     describe('#bulkUpdate', () => {
-      test(`supplements options with the spaces namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const expectedReturnValue = {
-          saved_objects: [createMockResponse()],
-        };
-        baseClient.bulkUpdate.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
+      test(`throws error if options.namespace is specified`, async () => {
+        const { client } = await createSpacesSavedObjectsClient();
 
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        await expect(
+          // @ts-ignore
+          client.bulkUpdate(null, { namespace: 'bar' })
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
+      });
+
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
+        const expectedReturnValue = { saved_objects: [createMockResponse()] };
+        baseClient.bulkUpdate.mockReturnValue(Promise.resolve(expectedReturnValue));
 
         const actualReturnValue = await client.bulkUpdate([
           { id: 'id', type: 'foo', attributes: {}, references: [] },
@@ -403,36 +297,18 @@ const createMockResponse = () => ({
 
     describe('#delete', () => {
       test(`throws error if options.namespace is specified`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
+        const { client } = await createSpacesSavedObjectsClient();
 
         await expect(
           // @ts-ignore
           client.delete(null, null, { namespace: 'bar' })
-        ).rejects.toThrowErrorMatchingSnapshot();
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
       });
 
-      test(`supplements options with undefined namespace`, async () => {
-        const request = createMockRequest();
-        const baseClient = createMockClient();
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
         const expectedReturnValue = createMockResponse();
         baseClient.delete.mockReturnValue(Promise.resolve(expectedReturnValue));
-        const spacesService = await createSpacesService(currentSpace.id);
-
-        const client = new SpacesSavedObjectsClient({
-          request,
-          baseClient,
-          spacesService,
-          typeRegistry,
-        });
 
         const type = Symbol();
         const id = Symbol();
@@ -447,5 +323,65 @@ const createMockResponse = () => ({
         });
       });
     });
+
+    describe('#addToNamespaces', () => {
+      test(`throws error if options.namespace is specified`, async () => {
+        const { client } = await createSpacesSavedObjectsClient();
+
+        await expect(
+          // @ts-ignore
+          client.addToNamespaces(null, null, null, { namespace: 'bar' })
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
+      });
+
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
+        const expectedReturnValue = createMockResponse();
+        baseClient.addToNamespaces.mockReturnValue(Promise.resolve(expectedReturnValue));
+
+        const type = Symbol();
+        const id = Symbol();
+        const namespaces = Symbol();
+        const options = Object.freeze({ foo: 'bar' });
+        // @ts-ignore
+        const actualReturnValue = await client.addToNamespaces(type, id, namespaces, options);
+
+        expect(actualReturnValue).toBe(expectedReturnValue);
+        expect(baseClient.addToNamespaces).toHaveBeenCalledWith(type, id, namespaces, {
+          foo: 'bar',
+          namespace: currentSpace.expectedNamespace,
+        });
+      });
+    });
+
+    describe('#deleteFromNamespaces', () => {
+      test(`throws error if options.namespace is specified`, async () => {
+        const { client } = await createSpacesSavedObjectsClient();
+
+        await expect(
+          // @ts-ignore
+          client.deleteFromNamespaces(null, null, null, { namespace: 'bar' })
+        ).rejects.toThrow(ERROR_NAMESPACE_SPECIFIED);
+      });
+
+      test(`supplements options with the current namespace`, async () => {
+        const { client, baseClient } = await createSpacesSavedObjectsClient();
+        const expectedReturnValue = createMockResponse();
+        baseClient.deleteFromNamespaces.mockReturnValue(Promise.resolve(expectedReturnValue));
+
+        const type = Symbol();
+        const id = Symbol();
+        const namespaces = Symbol();
+        const options = Object.freeze({ foo: 'bar' });
+        // @ts-ignore
+        const actualReturnValue = await client.deleteFromNamespaces(type, id, namespaces, options);
+
+        expect(actualReturnValue).toBe(expectedReturnValue);
+        expect(baseClient.deleteFromNamespaces).toHaveBeenCalledWith(type, id, namespaces, {
+          foo: 'bar',
+          namespace: currentSpace.expectedNamespace,
+        });
+      });
+    });
   });
 });
diff --git a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts
index f216d5743cf89..e31bc7cef6900 100644
--- a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts
+++ b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts
@@ -13,6 +13,8 @@ import {
   SavedObjectsCreateOptions,
   SavedObjectsFindOptions,
   SavedObjectsUpdateOptions,
+  SavedObjectsAddToNamespacesOptions,
+  SavedObjectsDeleteFromNamespacesOptions,
   ISavedObjectTypeRegistry,
 } from 'src/core/server';
 import { SpacesServiceSetup } from '../spaces_service/spaces_service';
@@ -213,6 +215,50 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract {
     });
   }
 
+  /**
+   * Adds namespaces to a SavedObject
+   *
+   * @param type
+   * @param id
+   * @param namespaces
+   * @param options
+   */
+  public async addToNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsAddToNamespacesOptions = {}
+  ) {
+    throwErrorIfNamespaceSpecified(options);
+
+    return await this.client.addToNamespaces(type, id, namespaces, {
+      ...options,
+      namespace: spaceIdToNamespace(this.spaceId),
+    });
+  }
+
+  /**
+   * Removes namespaces from a SavedObject
+   *
+   * @param type
+   * @param id
+   * @param namespaces
+   * @param options
+   */
+  public async deleteFromNamespaces(
+    type: string,
+    id: string,
+    namespaces: string[],
+    options: SavedObjectsDeleteFromNamespacesOptions = {}
+  ) {
+    throwErrorIfNamespaceSpecified(options);
+
+    return await this.client.deleteFromNamespaces(type, id, namespaces, {
+      ...options,
+      namespace: spaceIdToNamespace(this.spaceId),
+    });
+  }
+
   /**
    * Updates an array of objects by id
    *
diff --git a/x-pack/plugins/uptime/server/rest_api/types.ts b/x-pack/plugins/uptime/server/rest_api/types.ts
index aecb099b7bed5..e05e7a4d7faf1 100644
--- a/x-pack/plugins/uptime/server/rest_api/types.ts
+++ b/x-pack/plugins/uptime/server/rest_api/types.ts
@@ -10,7 +10,7 @@ import {
   RouteConfig,
   RouteMethod,
   CallAPIOptions,
-  SavedObjectsClient,
+  SavedObjectsClientContract,
   RequestHandlerContext,
   KibanaRequest,
   KibanaResponseFactory,
@@ -69,18 +69,7 @@ export interface UMRouteParams {
     options?: CallAPIOptions | undefined
   ) => Promise<any>;
   dynamicSettings: DynamicSettings;
-  savedObjectsClient: Pick<
-    SavedObjectsClient,
-    | 'errors'
-    | 'create'
-    | 'bulkCreate'
-    | 'delete'
-    | 'find'
-    | 'bulkGet'
-    | 'get'
-    | 'update'
-    | 'bulkUpdate'
-  >;
+  savedObjectsClient: SavedObjectsClientContract;
 }
 
 /**
diff --git a/x-pack/test/api_integration/apis/spaces/saved_objects.ts b/x-pack/test/api_integration/apis/spaces/saved_objects.ts
index 05f14a50f2170..7584be7fd8498 100644
--- a/x-pack/test/api_integration/apis/spaces/saved_objects.ts
+++ b/x-pack/test/api_integration/apis/spaces/saved_objects.ts
@@ -89,7 +89,7 @@ export default function({ getService }: FtrProviderContext) {
           .expect(404)
           .then((response: Record<string, any>) => {
             expect(response.body).to.eql({
-              message: 'Not Found',
+              message: 'Saved object [space/default] not found',
               statusCode: 404,
               error: 'Not Found',
             });
diff --git a/x-pack/test/saved_object_api_integration/common/config.ts b/x-pack/test/saved_object_api_integration/common/config.ts
index dda7934ce875a..eaf7230a832a8 100644
--- a/x-pack/test/saved_object_api_integration/common/config.ts
+++ b/x-pack/test/saved_object_api_integration/common/config.ts
@@ -56,8 +56,10 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
           ...config.xpack.api.get('kbnTestServer.serverArgs'),
           '--optimize.enabled=false',
           '--server.xsrf.disableProtection=true',
+          `--plugin-path=${path.join(__dirname, 'fixtures', 'isolated_type_plugin')}`,
           `--plugin-path=${path.join(__dirname, 'fixtures', 'namespace_agnostic_type_plugin')}`,
           `--plugin-path=${path.join(__dirname, 'fixtures', 'hidden_type_plugin')}`,
+          `--plugin-path=${path.join(__dirname, 'fixtures', 'shared_type_plugin')}`,
           ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`),
         ],
       },
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
index 34361ad9df542..d2c14189e2529 100644
--- a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
@@ -53,7 +53,7 @@
 {
   "type": "doc",
   "value": {
-    "id": "index-pattern:91200a00-9efd-11e7-acb3-3dab96693fab",
+    "id": "index-pattern:defaultspace-index-pattern-id",
     "index": ".kibana",
     "source": {
       "index-pattern": {
@@ -76,7 +76,7 @@
     "source": {
       "config": {
         "buildNum": 8467,
-        "defaultIndex": "91200a00-9efd-11e7-acb3-3dab96693fab"
+        "defaultIndex": "defaultspace-index-pattern-id"
       },
       "type": "config",
       "updated_at": "2017-09-21T18:49:16.302Z"
@@ -88,15 +88,15 @@
 {
   "type": "doc",
   "value": {
-    "id": "visualization:dd7caf20-9efd-11e7-acb3-3dab96693fab",
+    "id": "isolatedtype:defaultspace-isolatedtype-id",
     "index": ".kibana",
     "source": {
-      "type": "visualization",
+      "type": "isolatedtype",
       "updated_at": "2017-09-21T18:51:23.794Z",
-      "visualization": {
+      "isolatedtype": {
         "description": "",
         "kibanaSavedObjectMeta": {
-          "searchSourceJSON": "{\"index\":\"91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
+          "searchSourceJSON": "{\"index\":\"defaultspace-index-pattern-id\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
         },
         "title": "Count of requests",
         "uiStateJSON": "{\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}}",
@@ -111,7 +111,7 @@
 {
   "type": "doc",
   "value": {
-    "id": "dashboard:be3733a0-9efe-11e7-acb3-3dab96693fab",
+    "id": "dashboard:defaultspace-dashboard-id",
     "index": ".kibana",
     "source": {
       "dashboard": {
@@ -121,7 +121,7 @@
           "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
         },
         "optionsJSON": "{}",
-        "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
+        "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"isolatedtype\",\"id\":\"defaultspace-isolatedtype-id\",\"col\":1,\"row\":1}]",
         "refreshInterval": {
           "display": "Off",
           "pause": false,
@@ -144,7 +144,7 @@
 {
   "type": "doc",
   "value": {
-    "id": "space_1:index-pattern:space_1-91200a00-9efd-11e7-acb3-3dab96693fab",
+    "id": "space_1:index-pattern:space1-index-pattern-id",
     "index": ".kibana",
     "source": {
       "index-pattern": {
@@ -168,7 +168,7 @@
     "source": {
       "config": {
         "buildNum": 8467,
-        "defaultIndex": "91200a00-9efd-11e7-acb3-3dab96693fab"
+        "defaultIndex": "defaultspace-index-pattern-id"
       },
       "namespace": "space_1",
       "type": "config",
@@ -181,16 +181,16 @@
 {
   "type": "doc",
   "value": {
-    "id": "space_1:visualization:space_1-dd7caf20-9efd-11e7-acb3-3dab96693fab",
+    "id": "space_1:isolatedtype:space1-isolatedtype-id",
     "index": ".kibana",
     "source": {
       "namespace": "space_1",
-      "type": "visualization",
+      "type": "isolatedtype",
       "updated_at": "2017-09-21T18:51:23.794Z",
-      "visualization": {
+      "isolatedtype": {
         "description": "",
         "kibanaSavedObjectMeta": {
-          "searchSourceJSON": "{\"index\":\"space_1-91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
+          "searchSourceJSON": "{\"index\":\"space1-index-pattern-id\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
         },
         "title": "Count of requests",
         "uiStateJSON": "{\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}}",
@@ -205,7 +205,7 @@
 {
   "type": "doc",
   "value": {
-    "id": "space_1:dashboard:space_1-be3733a0-9efe-11e7-acb3-3dab96693fab",
+    "id": "space_1:dashboard:space1-dashboard-id",
     "index": ".kibana",
     "source": {
       "dashboard": {
@@ -215,7 +215,7 @@
           "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
         },
         "optionsJSON": "{}",
-        "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"space_1-dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
+        "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"isolatedtype\",\"id\":\"space1-isolatedtype-id\",\"col\":1,\"row\":1}]",
         "refreshInterval": {
           "display": "Off",
           "pause": false,
@@ -239,7 +239,7 @@
 {
   "type": "doc",
   "value": {
-    "id": "space_2:index-pattern:space_2-91200a00-9efd-11e7-acb3-3dab96693fab",
+    "id": "space_2:index-pattern:space2-index-pattern-id",
     "index": ".kibana",
     "source": {
       "index-pattern": {
@@ -263,7 +263,7 @@
     "source": {
       "config": {
         "buildNum": 8467,
-        "defaultIndex": "91200a00-9efd-11e7-acb3-3dab96693fab"
+        "defaultIndex": "defaultspace-index-pattern-id"
       },
       "namespace": "space_2",
       "type": "config",
@@ -276,16 +276,16 @@
 {
   "type": "doc",
   "value": {
-    "id": "space_2:visualization:space_2-dd7caf20-9efd-11e7-acb3-3dab96693fab",
+    "id": "space_2:isolatedtype:space2-isolatedtype-id",
     "index": ".kibana",
     "source": {
       "namespace": "space_2",
-      "type": "visualization",
+      "type": "isolatedtype",
       "updated_at": "2017-09-21T18:51:23.794Z",
-      "visualization": {
+      "isolatedtype": {
         "description": "",
         "kibanaSavedObjectMeta": {
-          "searchSourceJSON": "{\"index\":\"space_2-91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
+          "searchSourceJSON": "{\"index\":\"space2-index-pattern-id\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
         },
         "title": "Count of requests",
         "uiStateJSON": "{\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}}",
@@ -300,7 +300,7 @@
 {
   "type": "doc",
   "value": {
-    "id": "space_2:dashboard:space_2-be3733a0-9efe-11e7-acb3-3dab96693fab",
+    "id": "space_2:dashboard:space2-dashboard-id",
     "index": ".kibana",
     "source": {
       "dashboard": {
@@ -310,7 +310,7 @@
           "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
         },
         "optionsJSON": "{}",
-        "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"space_2-dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
+        "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"isolatedtype\",\"id\":\"space2-isolatedtype-id\",\"col\":1,\"row\":1}]",
         "refreshInterval": {
           "display": "Off",
           "pause": false,
@@ -334,11 +334,11 @@
 {
   "type": "doc",
   "value": {
-    "id": "globaltype:8121a00-8efd-21e7-1cb3-34ab966434445",
+    "id": "globaltype:globaltype-id",
     "index": ".kibana",
     "source": {
       "globaltype": {
-        "name": "My favorite global object"
+        "title": "My favorite global object"
       },
       "type": "globaltype",
       "updated_at": "2017-09-21T18:59:16.270Z"
@@ -346,3 +346,54 @@
     "type": "doc"
   }
 }
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:default_and_space_1",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the default and space_1 spaces"
+      },
+      "type": "sharedtype",
+      "namespaces": ["default", "space_1"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:only_space_1",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object only in space_1"
+      },
+      "type": "sharedtype",
+      "namespaces": ["space_1"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:only_space_2",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object only in space_2"
+      },
+      "type": "sharedtype",
+      "namespaces": ["space_2"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json
index c2489f2a906c8..7b5b1d86f6bcc 100644
--- a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json
@@ -82,7 +82,7 @@
         },
         "globaltype": {
           "properties": {
-            "name": {
+            "title": {
               "fields": {
                 "keyword": {
                   "ignore_above": 2048,
@@ -147,9 +147,41 @@
             }
           }
         },
+        "isolatedtype": {
+          "properties": {
+            "description": {
+              "type": "text"
+            },
+            "kibanaSavedObjectMeta": {
+              "properties": {
+                "searchSourceJSON": {
+                  "type": "text"
+                }
+              }
+            },
+            "savedSearchId": {
+              "type": "keyword"
+            },
+            "title": {
+              "type": "text"
+            },
+            "uiStateJSON": {
+              "type": "text"
+            },
+            "version": {
+              "type": "integer"
+            },
+            "visState": {
+              "type": "text"
+            }
+          }
+        },
         "namespace": {
           "type": "keyword"
         },
+        "namespaces": {
+          "type": "keyword"
+        },
         "search": {
           "properties": {
             "columns": {
@@ -186,6 +218,19 @@
             }
           }
         },
+        "sharedtype": {
+          "properties": {
+            "title": {
+              "type": "text",
+              "fields": {
+                "keyword": {
+                  "type": "keyword",
+                  "ignore_above": 2048
+                }
+              }
+            }
+          }
+        },
         "space": {
           "properties": {
             "_reserved": {
@@ -282,35 +327,6 @@
               "type": "text"
             }
           }
-        },
-        "visualization": {
-          "properties": {
-            "description": {
-              "type": "text"
-            },
-            "kibanaSavedObjectMeta": {
-              "properties": {
-                "searchSourceJSON": {
-                  "type": "text"
-                }
-              }
-            },
-            "savedSearchId": {
-              "type": "keyword"
-            },
-            "title": {
-              "type": "text"
-            },
-            "uiStateJSON": {
-              "type": "text"
-            },
-            "version": {
-              "type": "integer"
-            },
-            "visState": {
-              "type": "text"
-            }
-          }
         }
       }
     },
@@ -322,4 +338,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/index.js b/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/index.js
index ea32811794c47..5989db84e2290 100644
--- a/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/index.js
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/index.js
@@ -21,5 +21,7 @@ export default function(kibana) {
     },
 
     config() {},
+
+    init() {}, // need empty init for plugin to load
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/mappings.json b/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/mappings.json
index e4815273964a1..45f898e10e2ba 100644
--- a/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/mappings.json
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/hidden_type_plugin/mappings.json
@@ -1,7 +1,7 @@
 {
   "hiddentype": {
     "properties": {
-      "name": {
+      "title": {
         "type": "text",
         "fields": {
           "keyword": {
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/index.js b/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/index.js
new file mode 100644
index 0000000000000..a406c6737da5f
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/index.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import mappings from './mappings.json';
+
+export default function(kibana) {
+  return new kibana.Plugin({
+    require: ['kibana', 'elasticsearch', 'xpack_main'],
+    name: 'isolated_type_plugin',
+    uiExports: {
+      savedObjectsManagement: {
+        isolatedtype: {
+          isImportableAndExportable: true,
+        },
+      },
+      mappings,
+    },
+
+    config() {},
+
+    init() {}, // need empty init for plugin to load
+  });
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/mappings.json b/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/mappings.json
new file mode 100644
index 0000000000000..141ebbc93c290
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/mappings.json
@@ -0,0 +1,31 @@
+{
+  "isolatedtype": {
+    "properties": {
+      "description": {
+        "type": "text"
+      },
+      "kibanaSavedObjectMeta": {
+        "properties": {
+          "searchSourceJSON": {
+            "type": "text"
+          }
+        }
+      },
+      "savedSearchId": {
+        "type": "keyword"
+      },
+      "title": {
+        "type": "text"
+      },
+      "uiStateJSON": {
+        "type": "text"
+      },
+      "version": {
+        "type": "integer"
+      },
+      "visState": {
+        "type": "text"
+      }
+    }
+  }
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/package.json b/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/package.json
new file mode 100644
index 0000000000000..665ecb1b31d7e
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/isolated_type_plugin/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "isolated_type_plugin",
+  "version": "0.0.0",
+  "kibana": {
+    "version": "kibana"
+  }
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/namespace_agnostic_type_plugin/mappings.json b/x-pack/test/saved_object_api_integration/common/fixtures/namespace_agnostic_type_plugin/mappings.json
index b30a2c3877b88..64d309b4209a2 100644
--- a/x-pack/test/saved_object_api_integration/common/fixtures/namespace_agnostic_type_plugin/mappings.json
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/namespace_agnostic_type_plugin/mappings.json
@@ -1,7 +1,7 @@
 {
   "globaltype": {
     "properties": {
-      "name": {
+      "title": {
         "type": "text",
         "fields": {
           "keyword": {
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/index.js b/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/index.js
new file mode 100644
index 0000000000000..91a24fb9f4f56
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/index.js
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import mappings from './mappings.json';
+
+export default function(kibana) {
+  return new kibana.Plugin({
+    require: ['kibana', 'elasticsearch', 'xpack_main'],
+    name: 'shared_type_plugin',
+    uiExports: {
+      savedObjectsManagement: {},
+      savedObjectSchemas: {
+        sharedtype: {
+          multiNamespace: true,
+        },
+      },
+      mappings,
+    },
+
+    config() {},
+
+    init() {}, // need empty init for plugin to load
+  });
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/mappings.json b/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/mappings.json
new file mode 100644
index 0000000000000..918958aec0d6d
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/mappings.json
@@ -0,0 +1,15 @@
+{
+  "sharedtype": {
+    "properties": {
+      "title": {
+        "type": "text",
+        "fields": {
+          "keyword": {
+            "type": "keyword",
+            "ignore_above": 2048
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/package.json b/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/package.json
new file mode 100644
index 0000000000000..c52f4256c5c06
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/shared_type_plugin/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "shared_type_plugin",
+  "version": "0.0.0",
+  "kibana": {
+    "version": "kibana"
+  }
+}
diff --git a/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts
new file mode 100644
index 0000000000000..b32950538f8e5
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const SAVED_OBJECT_TEST_CASES = Object.freeze({
+  SINGLE_NAMESPACE_DEFAULT_SPACE: Object.freeze({
+    type: 'isolatedtype',
+    id: 'defaultspace-isolatedtype-id',
+  }),
+  SINGLE_NAMESPACE_SPACE_1: Object.freeze({
+    type: 'isolatedtype',
+    id: 'space1-isolatedtype-id',
+  }),
+  SINGLE_NAMESPACE_SPACE_2: Object.freeze({
+    type: 'isolatedtype',
+    id: 'space2-isolatedtype-id',
+  }),
+  MULTI_NAMESPACE_DEFAULT_AND_SPACE_1: Object.freeze({
+    type: 'sharedtype',
+    id: 'default_and_space_1',
+  }),
+  MULTI_NAMESPACE_ONLY_SPACE_1: Object.freeze({
+    type: 'sharedtype',
+    id: 'only_space_1',
+  }),
+  MULTI_NAMESPACE_ONLY_SPACE_2: Object.freeze({
+    type: 'sharedtype',
+    id: 'only_space_2',
+  }),
+  NAMESPACE_AGNOSTIC: Object.freeze({
+    type: 'globaltype',
+    id: 'globaltype-id',
+  }),
+  HIDDEN: Object.freeze({
+    type: 'hiddentype',
+    id: 'any',
+  }),
+});
diff --git a/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts
new file mode 100644
index 0000000000000..5640dfefa4f8d
--- /dev/null
+++ b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts
@@ -0,0 +1,302 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from '@kbn/expect';
+import { SavedObjectsErrorHelpers } from '../../../../../src/core/server';
+import { SAVED_OBJECT_TEST_CASES as CASES } from './saved_object_test_cases';
+import { SPACES } from './spaces';
+import { AUTHENTICATION } from './authentication';
+import { TestCase, TestUser, ExpectResponseBody } from './types';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const {
+  NOT_A_KIBANA_USER,
+  SUPERUSER,
+  KIBANA_LEGACY_USER,
+  KIBANA_DUAL_PRIVILEGES_USER,
+  KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
+  KIBANA_RBAC_USER,
+  KIBANA_RBAC_DASHBOARD_ONLY_USER,
+  KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
+  KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
+  KIBANA_RBAC_SPACE_1_ALL_USER,
+  KIBANA_RBAC_SPACE_1_READ_USER,
+} = AUTHENTICATION;
+
+export function getUrlPrefix(spaceId: string) {
+  return spaceId && spaceId !== DEFAULT_SPACE_ID ? `/s/${spaceId}` : ``;
+}
+
+export function getExpectedSpaceIdProperty(spaceId: string) {
+  if (spaceId === DEFAULT_SPACE_ID) {
+    return {};
+  }
+  return {
+    spaceId,
+  };
+}
+
+export const getTestTitle = (
+  testCaseOrCases: TestCase | TestCase[],
+  bulkStatusCode?: 200 | 403 // only used for bulk test suites; other suites specify forbidden/permitted in each test case
+) => {
+  const testCases = Array.isArray(testCaseOrCases) ? testCaseOrCases : [testCaseOrCases];
+  const stringify = (array: TestCase[]) => array.map(x => `${x.type}/${x.id}`).join();
+  if (bulkStatusCode === 403 || (testCases.length === 1 && testCases[0].failure === 403)) {
+    return `forbidden [${stringify(testCases)}]`;
+  }
+  if (testCases.find(x => x.failure === 403)) {
+    throw new Error(
+      'Cannot create test title for multiple forbidden test cases; specify individual tests for each of these test cases'
+    );
+  }
+  // permitted
+  const list: string[] = [];
+  Object.entries({
+    success: undefined,
+    'bad request': 400,
+    'not found': 404,
+    conflict: 409,
+  }).forEach(([descriptor, failure]) => {
+    const filtered = testCases.filter(x => x.failure === failure);
+    if (filtered.length) {
+      list.push(`${descriptor} [${stringify(filtered)}]`);
+    }
+  });
+  return `${list.join(' and ')}`;
+};
+
+export const testCaseFailures = {
+  // test suites need explicit return types for number primitives
+  fail400: (condition?: boolean): { failure?: 400 } =>
+    condition !== false ? { failure: 400 } : {},
+  fail404: (condition?: boolean): { failure?: 404 } =>
+    condition !== false ? { failure: 404 } : {},
+  fail409: (condition?: boolean): { failure?: 409 } =>
+    condition !== false ? { failure: 409 } : {},
+};
+
+/**
+ * Test cases have additional properties that we don't want to send in HTTP Requests
+ */
+export const createRequest = ({ type, id }: TestCase) => ({ type, id });
+
+const uniq = <T>(arr: T[]): T[] => Array.from(new Set<T>(arr));
+const isNamespaceAgnostic = (type: string) => type === 'globaltype';
+const isMultiNamespace = (type: string) => type === 'sharedtype';
+export const expectResponses = {
+  forbidden: (action: string) => (typeOrTypes: string | string[]): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
+    const uniqueSorted = uniq(types).sort();
+    expect(response.body).to.eql({
+      statusCode: 403,
+      error: 'Forbidden',
+      message: `Unable to ${action} ${uniqueSorted.join()}`,
+    });
+  },
+  permitted: async (object: Record<string, any>, testCase: TestCase) => {
+    const { type, id, failure } = testCase;
+    if (failure) {
+      let error: ReturnType<typeof SavedObjectsErrorHelpers['decorateGeneralError']>;
+      if (failure === 400) {
+        error = SavedObjectsErrorHelpers.createUnsupportedTypeError(type);
+      } else if (failure === 404) {
+        error = SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
+      } else if (failure === 409) {
+        error = SavedObjectsErrorHelpers.createConflictError(type, id);
+      } else {
+        throw new Error(`Encountered unexpected error code ${failure}`);
+      }
+      // should not call permitted with a 403 failure case
+      if (object.type && object.id) {
+        // bulk request error
+        expect(object.type).to.eql(type);
+        expect(object.id).to.eql(id);
+        expect(object.error).to.eql(error.output.payload);
+      } else {
+        // non-bulk request error
+        expect(object.error).to.eql(error.output.payload.error);
+        expect(object.statusCode).to.eql(error.output.payload.statusCode);
+        // ignore the error.message, because it can vary for decorated non-bulk errors (e.g., conflict)
+      }
+    } else {
+      // fall back to default behavior of testing the success outcome
+      expect(object.type).to.eql(type);
+      if (id) {
+        expect(object.id).to.eql(id);
+      } else {
+        // created an object without specifying the ID, so it was auto-generated
+        expect(object.id).to.match(/^[0-9a-f-]{36}$/);
+      }
+      expect(object).not.to.have.property('error');
+      expect(object.updated_at).to.match(/^[\d-]{10}T[\d:\.]{12}Z$/);
+      // don't test attributes, version, or references
+    }
+  },
+  /**
+   * Additional assertions that we use in `bulk_create` and `create` to ensure that
+   * newly-created (or overwritten) objects don't have unexpected properties
+   */
+  successCreated: async (es: any, spaceId: string, type: string, id: string) => {
+    const isNamespaceUndefined =
+      spaceId === SPACES.DEFAULT.spaceId || isNamespaceAgnostic(type) || isMultiNamespace(type);
+    const expectedSpacePrefix = isNamespaceUndefined ? '' : `${spaceId}:`;
+    const savedObject = await es.get({
+      id: `${expectedSpacePrefix}${type}:${id}`,
+      index: '.kibana',
+    });
+    const { namespace: actualNamespace, namespaces: actualNamespaces } = savedObject._source;
+    if (isNamespaceUndefined) {
+      expect(actualNamespace).to.eql(undefined);
+    } else {
+      expect(actualNamespace).to.eql(spaceId);
+    }
+    if (isMultiNamespace(type)) {
+      if (id === CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1.id) {
+        expect(actualNamespaces).to.eql([DEFAULT_SPACE_ID, SPACE_1_ID]);
+      } else if (id === CASES.MULTI_NAMESPACE_ONLY_SPACE_1.id) {
+        expect(actualNamespaces).to.eql([SPACE_1_ID]);
+      } else if (id === CASES.MULTI_NAMESPACE_ONLY_SPACE_2.id) {
+        expect(actualNamespaces).to.eql([SPACE_2_ID]);
+      } else {
+        // newly created in this space
+        expect(actualNamespaces).to.eql([spaceId]);
+      }
+    }
+    return savedObject;
+  },
+};
+
+/**
+ * Get test scenarios for each type of suite.
+ * @param modifier Use this to generate additional permutations of test scenarios.
+ *  For instance, a modifier of ['foo', 'bar'] would return
+ *  a `securityAndSpaces` of: [
+ *    { spaceId: DEFAULT_SPACE_ID, users: {...}, modifier: 'foo' },
+ *    { spaceId: DEFAULT_SPACE_ID, users: {...}, modifier: 'bar' },
+ *    { spaceId: SPACE_1_ID, users: {...}, modifier: 'foo' },
+ *    { spaceId: SPACE_1_ID, users: {...}, modifier: 'bar' },
+ *  ]
+ */
+export const getTestScenarios = <T>(modifiers?: T[]) => {
+  const commonUsers = {
+    noAccess: { ...NOT_A_KIBANA_USER, description: 'user with no access' },
+    superuser: { ...SUPERUSER, description: 'superuser' },
+    legacyAll: { ...KIBANA_LEGACY_USER, description: 'legacy user' },
+    allGlobally: { ...KIBANA_RBAC_USER, description: 'rbac user with all globally' },
+    readGlobally: {
+      ...KIBANA_RBAC_DASHBOARD_ONLY_USER,
+      description: 'rbac user with read globally',
+    },
+    dualAll: { ...KIBANA_DUAL_PRIVILEGES_USER, description: 'dual-privileges user' },
+    dualRead: {
+      ...KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
+      description: 'dual-privileges readonly user',
+    },
+  };
+
+  interface Security {
+    modifier?: T;
+    users: Record<
+      | keyof typeof commonUsers
+      | 'allAtDefaultSpace'
+      | 'readAtDefaultSpace'
+      | 'allAtSpace1'
+      | 'readAtSpace1',
+      TestUser
+    >;
+  }
+  interface SecurityAndSpaces {
+    modifier?: T;
+    users: Record<
+      keyof typeof commonUsers | 'allAtSpace' | 'readAtSpace' | 'allAtOtherSpace',
+      TestUser
+    >;
+    spaceId: string;
+  }
+  interface Spaces {
+    modifier?: T;
+    spaceId: string;
+  }
+
+  let spaces: Spaces[] = [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID].map(x => ({ spaceId: x }));
+  let security: Security[] = [
+    {
+      users: {
+        ...commonUsers,
+        allAtDefaultSpace: {
+          ...KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
+          description: 'rbac user with all at default space',
+        },
+        readAtDefaultSpace: {
+          ...KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
+          description: 'rbac user with read at default space',
+        },
+        allAtSpace1: {
+          ...KIBANA_RBAC_SPACE_1_ALL_USER,
+          description: 'rbac user with all at space_1',
+        },
+        readAtSpace1: {
+          ...KIBANA_RBAC_SPACE_1_READ_USER,
+          description: 'rbac user with read at space_1',
+        },
+      },
+    },
+  ];
+  let securityAndSpaces: SecurityAndSpaces[] = [
+    {
+      spaceId: DEFAULT_SPACE_ID,
+      users: {
+        ...commonUsers,
+        allAtSpace: {
+          ...KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
+          description: 'user with all at the space',
+        },
+        readAtSpace: {
+          ...KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
+          description: 'user with read at the space',
+        },
+        allAtOtherSpace: {
+          ...KIBANA_RBAC_SPACE_1_ALL_USER,
+          description: 'user with all at other space',
+        },
+      },
+    },
+    {
+      spaceId: SPACE_1_ID,
+      users: {
+        ...commonUsers,
+        allAtSpace: { ...KIBANA_RBAC_SPACE_1_ALL_USER, description: 'user with all at the space' },
+        readAtSpace: {
+          ...KIBANA_RBAC_SPACE_1_READ_USER,
+          description: 'user with read at the space',
+        },
+        allAtOtherSpace: {
+          ...KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
+          description: 'user with all at other space',
+        },
+      },
+    },
+  ];
+  if (modifiers) {
+    const addModifier = <T>(list: T[]) =>
+      list.map(x => modifiers.map(modifier => ({ ...x, modifier }))).flat();
+    spaces = addModifier(spaces);
+    security = addModifier(security);
+    securityAndSpaces = addModifier(securityAndSpaces);
+  }
+  return {
+    spaces,
+    security,
+    securityAndSpaces,
+  };
+};
diff --git a/x-pack/test/saved_object_api_integration/common/lib/space_test_utils.ts b/x-pack/test/saved_object_api_integration/common/lib/space_test_utils.ts
deleted file mode 100644
index 1619d77761c84..0000000000000
--- a/x-pack/test/saved_object_api_integration/common/lib/space_test_utils.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-
-export function getUrlPrefix(spaceId: string) {
-  return spaceId && spaceId !== DEFAULT_SPACE_ID ? `/s/${spaceId}` : ``;
-}
-
-export function getIdPrefix(spaceId: string) {
-  return spaceId === DEFAULT_SPACE_ID ? '' : `${spaceId}-`;
-}
-
-export function getExpectedSpaceIdProperty(spaceId: string) {
-  if (spaceId === DEFAULT_SPACE_ID) {
-    return {};
-  }
-  return {
-    spaceId,
-  };
-}
diff --git a/x-pack/test/saved_object_api_integration/common/lib/types.ts b/x-pack/test/saved_object_api_integration/common/lib/types.ts
index 487afff1494c0..f6e6d391ae905 100644
--- a/x-pack/test/saved_object_api_integration/common/lib/types.ts
+++ b/x-pack/test/saved_object_api_integration/common/lib/types.ts
@@ -4,9 +4,28 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-export type DescribeFn = (text: string, fn: () => void) => void;
+export type ExpectResponseBody = (response: Record<string, any>) => Promise<void>;
 
-export interface TestDefinitionAuthentication {
-  username?: string;
-  password?: string;
+export interface TestDefinition {
+  title: string;
+  responseStatusCode: number;
+  responseBody: ExpectResponseBody;
+}
+
+export interface TestSuite<T> {
+  user?: TestUser;
+  spaceId?: string;
+  tests: T[];
+}
+
+export interface TestCase {
+  type: string;
+  id: string;
+  failure?: 400 | 403 | 404 | 409;
+}
+
+export interface TestUser {
+  username: string;
+  password: string;
+  description: string;
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts b/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts
index b6f1bb956d72d..0dafe6b7b386d 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts
@@ -6,224 +6,137 @@
 
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface BulkCreateTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
-}
-
-interface BulkCreateCustomTest extends BulkCreateTest {
-  description: string;
-  requestBody: {
-    [key: string]: any;
-  };
-}
-
-interface BulkCreateTests {
-  default: BulkCreateTest;
-  includingSpace: BulkCreateTest;
-  custom?: BulkCreateCustomTest;
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface BulkCreateTestDefinition extends TestDefinition {
+  request: Array<{ type: string; id: string }>;
+  overwrite: boolean;
 }
-
-interface BulkCreateTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  tests: BulkCreateTests;
+export type BulkCreateTestSuite = TestSuite<BulkCreateTestDefinition>;
+export interface BulkCreateTestCase extends TestCase {
+  failure?: 400 | 409; // only used for permitted response case
 }
 
-const createBulkRequests = (spaceId: string) => [
-  {
-    type: 'visualization',
-    id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-    attributes: {
-      title: 'An existing visualization',
-    },
-  },
-  {
-    type: 'dashboard',
-    id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-    attributes: {
-      title: 'A great new dashboard',
-    },
-  },
-  {
-    type: 'globaltype',
-    id: '05976c65-1145-4858-bbf0-d225cc78a06e',
-    attributes: {
-      name: 'A new globaltype object',
-    },
-  },
-  {
-    type: 'globaltype',
-    id: '8121a00-8efd-21e7-1cb3-34ab966434445',
-    attributes: {
-      name: 'An existing globaltype',
-    },
-  },
-];
+const NEW_ATTRIBUTE_KEY = 'title'; // all type mappings include this attribute, for simplicity's sake
+const NEW_ATTRIBUTE_VAL = `New attribute value ${Date.now()}`;
 
-const isGlobalType = (type: string) => type === 'globaltype';
+const NEW_SINGLE_NAMESPACE_OBJ = Object.freeze({ type: 'dashboard', id: 'new-dashboard-id' });
+const NEW_MULTI_NAMESPACE_OBJ = Object.freeze({ type: 'sharedtype', id: 'new-sharedtype-id' });
+const NEW_NAMESPACE_AGNOSTIC_OBJ = Object.freeze({ type: 'globaltype', id: 'new-globaltype-id' });
+export const TEST_CASES = Object.freeze({
+  ...CASES,
+  NEW_SINGLE_NAMESPACE_OBJ,
+  NEW_MULTI_NAMESPACE_OBJ,
+  NEW_NAMESPACE_AGNOSTIC_OBJ,
+});
 
 export function bulkCreateTestSuiteFactory(es: any, esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectResults = (spaceId = DEFAULT_SPACE_ID) => async (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      saved_objects: [
-        {
-          type: 'visualization',
-          id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-          error: {
-            message: 'version conflict, document already exists',
-            statusCode: 409,
-          },
-        },
-        {
-          type: 'dashboard',
-          id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-          updated_at: resp.body.saved_objects[1].updated_at,
-          version: resp.body.saved_objects[1].version,
-          attributes: {
-            title: 'A great new dashboard',
-          },
-          references: [],
-        },
-        {
-          type: 'globaltype',
-          id: `05976c65-1145-4858-bbf0-d225cc78a06e`,
-          updated_at: resp.body.saved_objects[2].updated_at,
-          version: resp.body.saved_objects[2].version,
-          attributes: {
-            name: 'A new globaltype object',
-          },
-          references: [],
-        },
-        {
-          type: 'globaltype',
-          id: '8121a00-8efd-21e7-1cb3-34ab966434445',
-          error: {
-            message: 'version conflict, document already exists',
-            statusCode: 409,
-          },
-        },
-      ],
-    });
-
-    for (const savedObject of createBulkRequests(spaceId)) {
-      const expectedSpacePrefix =
-        spaceId === DEFAULT_SPACE_ID || isGlobalType(savedObject.type) ? '' : `${spaceId}:`;
-
-      // query ES directory to ensure namespace was or wasn't specified
-      const { _source } = await es.get({
-        id: `${expectedSpacePrefix}${savedObject.type}:${savedObject.id}`,
-        index: '.kibana',
-      });
-
-      const { namespace: actualNamespace } = _source;
-
-      if (spaceId === DEFAULT_SPACE_ID || isGlobalType(savedObject.type)) {
-        expect(actualNamespace).to.eql(undefined);
-      } else {
-        expect(actualNamespace).to.eql(spaceId);
+  const expectForbidden = expectResponses.forbidden('bulk_create');
+  const expectResponseBody = (
+    testCases: BulkCreateTestCase | BulkCreateTestCase[],
+    statusCode: 200 | 403,
+    spaceId = SPACES.DEFAULT.spaceId
+  ): ExpectResponseBody => async (response: Record<string, any>) => {
+    const testCaseArray = Array.isArray(testCases) ? testCases : [testCases];
+    if (statusCode === 403) {
+      const types = testCaseArray.map(x => x.type);
+      await expectForbidden(types)(response);
+    } else {
+      // permitted
+      const savedObjects = response.body.saved_objects;
+      expect(savedObjects).length(testCaseArray.length);
+      for (let i = 0; i < savedObjects.length; i++) {
+        const object = savedObjects[i];
+        const testCase = testCaseArray[i];
+        await expectResponses.permitted(object, testCase);
+        if (!testCase.failure) {
+          expect(object.attributes[NEW_ATTRIBUTE_KEY]).to.eql(NEW_ATTRIBUTE_VAL);
+          await expectResponses.successCreated(es, spaceId, object.type, object.id);
+        }
       }
     }
   };
-
-  const expectBadRequestForHiddenType = (resp: { [key: string]: any }) => {
-    const spaceEntry = resp.body.saved_objects.find(
-      (entry: any) => entry.id === 'my-hiddentype' && entry.type === 'hiddentype'
-    );
-    expect(spaceEntry).to.eql({
-      id: 'my-hiddentype',
-      type: 'hiddentype',
-      error: {
-        message: "Unsupported saved object type: 'hiddentype': Bad Request",
-        statusCode: 400,
-        error: 'Bad Request',
+  const createTestDefinitions = (
+    testCases: BulkCreateTestCase | BulkCreateTestCase[],
+    forbidden: boolean,
+    overwrite: boolean,
+    options?: {
+      spaceId?: string;
+      singleRequest?: boolean;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): BulkCreateTestDefinition[] => {
+    const cases = Array.isArray(testCases) ? testCases : [testCases];
+    const responseStatusCode = forbidden ? 403 : 200;
+    if (!options?.singleRequest) {
+      // if we are testing cases that should result in a forbidden response, we can do each case individually
+      // this ensures that multiple test cases of a single type will each result in a forbidden error
+      return cases.map(x => ({
+        title: getTestTitle(x, responseStatusCode),
+        request: [createRequest(x)],
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride ||
+          expectResponseBody(x, responseStatusCode, options?.spaceId),
+        overwrite,
+      }));
+    }
+    // batch into a single request to save time during test execution
+    return [
+      {
+        title: getTestTitle(cases, responseStatusCode),
+        request: cases.map(x => createRequest(x)),
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride ||
+          expectResponseBody(cases, responseStatusCode, options?.spaceId),
+        overwrite,
       },
-    });
+    ];
   };
 
-  const expectedForbiddenTypes = ['dashboard', 'globaltype', 'visualization'];
-  const expectedForbiddenTypesWithHiddenType = [
-    'dashboard',
-    'globaltype',
-    'hiddentype',
-    'visualization',
-  ];
-  const createExpectRbacForbidden = (types: string[] = expectedForbiddenTypes) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to bulk_create ${types.join(',')}`,
-    });
-  };
-
-  const makeBulkCreateTest = (describeFn: DescribeFn) => (
+  const makeBulkCreateTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: BulkCreateTestDefinition
+    definition: BulkCreateTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`should return ${tests.default.statusCode}`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_create`)
-          .auth(user.username, user.password)
-          .send(createBulkRequests(spaceId))
-          .expect(tests.default.statusCode)
-          .then(tests.default.response);
-      });
-
-      it(`including a hiddentype saved object should return ${tests.includingSpace.statusCode}`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_create`)
-          .auth(user.username, user.password)
-          .send(
-            createBulkRequests(spaceId).concat([
-              {
-                type: 'hiddentype',
-                id: `my-hiddentype`,
-                attributes: {
-                  name: 'My awesome hiddentype',
-                },
-              },
-            ])
-          )
-          .expect(tests.includingSpace.statusCode)
-          .then(tests.includingSpace.response);
-      });
+      const attrs = { attributes: { [NEW_ATTRIBUTE_KEY]: NEW_ATTRIBUTE_VAL } };
 
-      if (tests.custom) {
-        it(tests.custom!.description, async () => {
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const requestBody = test.request.map(x => ({ ...x, ...attrs }));
+          const query = test.overwrite ? '?overwrite=true' : '';
           await supertest
-            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_create`)
-            .auth(user.username, user.password)
-            .send(tests.custom!.requestBody)
-            .expect(tests.custom!.statusCode)
-            .then(tests.custom!.response);
+            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_create${query}`)
+            .auth(user?.username, user?.password)
+            .send(requestBody)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
       }
     });
   };
 
-  const bulkCreateTest = makeBulkCreateTest(describe);
+  const addTests = makeBulkCreateTest(describe);
   // @ts-ignore
-  bulkCreateTest.only = makeBulkCreateTest(describe.only);
+  addTests.only = makeBulkCreateTest(describe.only);
 
   return {
-    bulkCreateTest,
-    createExpectResults,
-    createExpectRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectedForbiddenTypesWithHiddenType,
+    addTests,
+    createTestDefinitions,
+    expectForbidden,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts b/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts
index 9c5cc375502d1..f03dac597294c 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts
@@ -6,203 +6,110 @@
 
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
 
-interface BulkGetTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
+export interface BulkGetTestDefinition extends TestDefinition {
+  request: Array<{ type: string; id: string }>;
 }
-
-interface BulkGetTests {
-  default: BulkGetTest;
-  includingHiddenType: BulkGetTest;
-}
-
-interface BulkGetTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  otherSpaceId?: string;
-  tests: BulkGetTests;
+export type BulkGetTestSuite = TestSuite<BulkGetTestDefinition>;
+export interface BulkGetTestCase extends TestCase {
+  failure?: 400 | 404; // only used for permitted response case
 }
 
-const createBulkRequests = (spaceId: string) => [
-  {
-    type: 'visualization',
-    id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-  },
-  {
-    type: 'dashboard',
-    id: `${getIdPrefix(spaceId)}does not exist`,
-  },
-  {
-    type: 'globaltype',
-    id: '8121a00-8efd-21e7-1cb3-34ab966434445',
-  },
-];
+const DOES_NOT_EXIST = Object.freeze({ type: 'dashboard', id: 'does-not-exist' });
+export const TEST_CASES = Object.freeze({ ...CASES, DOES_NOT_EXIST });
 
 export function bulkGetTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectNotFoundResults = (spaceId: string) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      saved_objects: [
-        {
-          id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-          type: 'visualization',
-          error: {
-            statusCode: 404,
-            message: 'Not found',
-          },
-        },
-        {
-          id: `${getIdPrefix(spaceId)}does not exist`,
-          type: 'dashboard',
-          error: {
-            statusCode: 404,
-            message: 'Not found',
-          },
-        },
-        {
-          id: `8121a00-8efd-21e7-1cb3-34ab966434445`,
-          type: 'globaltype',
-          updated_at: '2017-09-21T18:59:16.270Z',
-          version: resp.body.saved_objects[2].version,
-          attributes: {
-            name: 'My favorite global object',
-          },
-          references: [],
-        },
-      ],
-    });
+  const expectForbidden = expectResponses.forbidden('bulk_get');
+  const expectResponseBody = (
+    testCases: BulkGetTestCase | BulkGetTestCase[],
+    statusCode: 200 | 403
+  ): ExpectResponseBody => async (response: Record<string, any>) => {
+    const testCaseArray = Array.isArray(testCases) ? testCases : [testCases];
+    if (statusCode === 403) {
+      const types = testCaseArray.map(x => x.type);
+      await expectForbidden(types)(response);
+    } else {
+      // permitted
+      const savedObjects = response.body.saved_objects;
+      expect(savedObjects).length(testCaseArray.length);
+      for (let i = 0; i < savedObjects.length; i++) {
+        const object = savedObjects[i];
+        const testCase = testCaseArray[i];
+        await expectResponses.permitted(object, testCase);
+      }
+    }
   };
-
-  const expectBadRequestForHiddenType = (resp: { [key: string]: any }) => {
-    const spaceEntry = resp.body.saved_objects.find(
-      (entry: any) => entry.id === 'my-hiddentype' && entry.type === 'hiddentype'
-    );
-    expect(spaceEntry).to.eql({
-      id: 'my-hiddentype',
-      type: 'hiddentype',
-      error: {
-        message: "Unsupported saved object type: 'hiddentype': Bad Request",
-        statusCode: 400,
-        error: 'Bad Request',
+  const createTestDefinitions = (
+    testCases: BulkGetTestCase | BulkGetTestCase[],
+    forbidden: boolean,
+    options?: {
+      singleRequest?: boolean;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): BulkGetTestDefinition[] => {
+    const cases = Array.isArray(testCases) ? testCases : [testCases];
+    const responseStatusCode = forbidden ? 403 : 200;
+    if (!options?.singleRequest) {
+      // if we are testing cases that should result in a forbidden response, we can do each case individually
+      // this ensures that multiple test cases of a single type will each result in a forbidden error
+      return cases.map(x => ({
+        title: getTestTitle(x, responseStatusCode),
+        request: [createRequest(x)],
+        responseStatusCode,
+        responseBody: options?.responseBodyOverride || expectResponseBody(x, responseStatusCode),
+      }));
+    }
+    // batch into a single request to save time during test execution
+    return [
+      {
+        title: getTestTitle(cases, responseStatusCode),
+        request: cases.map(x => createRequest(x)),
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride || expectResponseBody(cases, responseStatusCode),
       },
-    });
+    ];
   };
 
-  const expectedForbiddenTypes = ['dashboard', 'globaltype', 'visualization'];
-  const expectedForbiddenTypesWithHiddenType = [
-    'dashboard',
-    'globaltype',
-    'hiddentype',
-    'visualization',
-  ];
-  const createExpectRbacForbidden = (types: string[] = expectedForbiddenTypes) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to bulk_get ${types.join(',')}`,
-    });
-  };
-
-  const createExpectResults = (spaceId = DEFAULT_SPACE_ID) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      saved_objects: [
-        {
-          id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-          type: 'visualization',
-          migrationVersion: resp.body.saved_objects[0].migrationVersion,
-          updated_at: '2017-09-21T18:51:23.794Z',
-          version: resp.body.saved_objects[0].version,
-          attributes: {
-            title: 'Count of requests',
-            description: '',
-            version: 1,
-            // cheat for some of the more complex attributes
-            visState: resp.body.saved_objects[0].attributes.visState,
-            uiStateJSON: resp.body.saved_objects[0].attributes.uiStateJSON,
-            kibanaSavedObjectMeta: resp.body.saved_objects[0].attributes.kibanaSavedObjectMeta,
-          },
-          references: [
-            {
-              name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
-              type: 'index-pattern',
-              id: `${getIdPrefix(spaceId)}91200a00-9efd-11e7-acb3-3dab96693fab`,
-            },
-          ],
-        },
-        {
-          id: `${getIdPrefix(spaceId)}does not exist`,
-          type: 'dashboard',
-          error: {
-            statusCode: 404,
-            message: 'Not found',
-          },
-        },
-        {
-          id: `8121a00-8efd-21e7-1cb3-34ab966434445`,
-          type: 'globaltype',
-          updated_at: '2017-09-21T18:59:16.270Z',
-          version: resp.body.saved_objects[2].version,
-          attributes: {
-            name: 'My favorite global object',
-          },
-          references: [],
-        },
-      ],
-    });
-  };
-
-  const makeBulkGetTest = (describeFn: DescribeFn) => (
+  const makeBulkGetTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: BulkGetTestDefinition
+    definition: BulkGetTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, otherSpaceId, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`should return ${tests.default.statusCode}`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_get`)
-          .auth(user.username, user.password)
-          .send(createBulkRequests(otherSpaceId || spaceId))
-          .expect(tests.default.statusCode)
-          .then(tests.default.response);
-      });
-
-      it(`with a hiddentype saved object included should return ${tests.includingHiddenType.statusCode}`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_get`)
-          .auth(user.username, user.password)
-          .send(
-            createBulkRequests(otherSpaceId || spaceId).concat([
-              {
-                type: 'hiddentype',
-                id: `my-hiddentype`,
-              },
-            ])
-          )
-          .expect(tests.includingHiddenType.statusCode)
-          .then(tests.includingHiddenType.response);
-      });
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          await supertest
+            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_get`)
+            .auth(user?.username, user?.password)
+            .send(test.request)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
+        });
+      }
     });
   };
 
-  const bulkGetTest = makeBulkGetTest(describe);
+  const addTests = makeBulkGetTest(describe);
   // @ts-ignore
-  bulkGetTest.only = makeBulkGetTest(describe.only);
+  addTests.only = makeBulkGetTest(describe.only);
 
   return {
-    bulkGetTest,
-    createExpectNotFoundResults,
-    createExpectResults,
-    createExpectRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectedForbiddenTypesWithHiddenType,
+    addTests,
+    createTestDefinitions,
+    expectForbidden,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/bulk_update.ts b/x-pack/test/saved_object_api_integration/common/suites/bulk_update.ts
index d14c5ccbd1d0e..e0e2118300ef4 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/bulk_update.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/bulk_update.ts
@@ -6,234 +6,119 @@
 
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface BulkUpdateTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
-}
-
-interface BulkUpdateTests {
-  spaceAware: BulkUpdateTest;
-  notSpaceAware: BulkUpdateTest;
-  hiddenType: BulkUpdateTest;
-  doesntExist: BulkUpdateTest;
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface BulkUpdateTestDefinition extends TestDefinition {
+  request: Array<{ type: string; id: string }>;
 }
-
-interface BulkUpdateTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  otherSpaceId?: string;
-  tests: BulkUpdateTests;
+export type BulkUpdateTestSuite = TestSuite<BulkUpdateTestDefinition>;
+export interface BulkUpdateTestCase extends TestCase {
+  failure?: 404; // only used for permitted response case
 }
 
-export function bulkUpdateTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectNotFound = (type: string, id: string, spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    const [, savedObject] = resp.body.saved_objects;
-    expect(savedObject.error).eql({
-      statusCode: 404,
-      error: 'Not Found',
-      message: `Saved object [${type}/${getIdPrefix(spaceId)}${id}] not found`,
-    });
-  };
-
-  const createExpectDoesntExistNotFound = (spaceId?: string) => {
-    return createExpectNotFound('visualization', 'not an id', spaceId);
-  };
-
-  const createExpectSpaceAwareNotFound = (spaceId?: string) => {
-    return createExpectNotFound('visualization', 'dd7caf20-9efd-11e7-acb3-3dab96693fab', spaceId);
-  };
-
-  const expectHiddenTypeNotFound = createExpectNotFound(
-    'hiddentype',
-    'hiddentype_1',
-    DEFAULT_SPACE_ID
-  );
-
-  const createExpectRbacForbidden = (types: string[]) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to bulk_update ${types.join()}`,
-    });
-  };
-
-  const expectDoesntExistRbacForbidden = createExpectRbacForbidden(['globaltype', 'visualization']);
+const NEW_ATTRIBUTE_KEY = 'title'; // all type mappings include this attribute, for simplicity's sake
+const NEW_ATTRIBUTE_VAL = `Updated attribute value ${Date.now()}`;
 
-  const expectNotSpaceAwareRbacForbidden = createExpectRbacForbidden(['globaltype']);
+const DOES_NOT_EXIST = Object.freeze({ type: 'dashboard', id: 'does-not-exist' });
+export const TEST_CASES = Object.freeze({ ...CASES, DOES_NOT_EXIST });
 
-  const expectHiddenTypeRbacForbidden = createExpectRbacForbidden(['globaltype', 'hiddentype']);
-  const expectHiddenTypeRbacForbiddenWithGlobalAllowed = createExpectRbacForbidden(['hiddentype']);
-
-  const expectSpaceAwareRbacForbidden = createExpectRbacForbidden(['globaltype', 'visualization']);
-
-  const expectNotSpaceAwareResults = (resp: { [key: string]: any }) => {
-    const [, savedObject] = resp.body.saved_objects;
-    // loose uuid validation
-    expect(savedObject)
-      .to.have.property('id')
-      .match(/^[0-9a-f-]{36}$/);
-
-    // loose ISO8601 UTC time with milliseconds validation
-    expect(savedObject)
-      .to.have.property('updated_at')
-      .match(/^[\d-]{10}T[\d:\.]{12}Z$/);
-
-    expect(savedObject).to.eql({
-      id: savedObject.id,
-      type: 'globaltype',
-      updated_at: savedObject.updated_at,
-      version: savedObject.version,
-      attributes: {
-        name: 'My second favorite',
-      },
-    });
+export function bulkUpdateTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
+  const expectForbidden = expectResponses.forbidden('bulk_update');
+  const expectResponseBody = (
+    testCases: BulkUpdateTestCase | BulkUpdateTestCase[],
+    statusCode: 200 | 403
+  ): ExpectResponseBody => async (response: Record<string, any>) => {
+    const testCaseArray = Array.isArray(testCases) ? testCases : [testCases];
+    if (statusCode === 403) {
+      const types = testCaseArray.map(x => x.type);
+      await expectForbidden(types)(response);
+    } else {
+      // permitted
+      const savedObjects = response.body.saved_objects;
+      expect(savedObjects).length(testCaseArray.length);
+      for (let i = 0; i < savedObjects.length; i++) {
+        const object = savedObjects[i];
+        const testCase = testCaseArray[i];
+        await expectResponses.permitted(object, testCase);
+        if (!testCase.failure) {
+          expect(object.attributes[NEW_ATTRIBUTE_KEY]).to.eql(NEW_ATTRIBUTE_VAL);
+        }
+      }
+    }
   };
-
-  const expectSpaceAwareResults = (resp: { [key: string]: any }) => {
-    const [, savedObject] = resp.body.saved_objects;
-    // loose uuid validation ignoring prefix
-    expect(savedObject)
-      .to.have.property('id')
-      .match(/[0-9a-f-]{36}$/);
-
-    // loose ISO8601 UTC time with milliseconds validation
-    expect(savedObject)
-      .to.have.property('updated_at')
-      .match(/^[\d-]{10}T[\d:\.]{12}Z$/);
-
-    expect(savedObject).to.eql({
-      id: savedObject.id,
-      type: 'visualization',
-      updated_at: savedObject.updated_at,
-      version: savedObject.version,
-      attributes: {
-        title: 'My second favorite vis',
+  const createTestDefinitions = (
+    testCases: BulkUpdateTestCase | BulkUpdateTestCase[],
+    forbidden: boolean,
+    options?: {
+      singleRequest?: boolean;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): BulkUpdateTestDefinition[] => {
+    const cases = Array.isArray(testCases) ? testCases : [testCases];
+    const responseStatusCode = forbidden ? 403 : 200;
+    if (!options?.singleRequest) {
+      // if we are testing cases that should result in a forbidden response, we can do each case individually
+      // this ensures that multiple test cases of a single type will each result in a forbidden error
+      return cases.map(x => ({
+        title: getTestTitle(x, responseStatusCode),
+        request: [createRequest(x)],
+        responseStatusCode,
+        responseBody: options?.responseBodyOverride || expectResponseBody(x, responseStatusCode),
+      }));
+    }
+    // batch into a single request to save time during test execution
+    return [
+      {
+        title: getTestTitle(cases, responseStatusCode),
+        request: cases.map(x => createRequest(x)),
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride || expectResponseBody(cases, responseStatusCode),
       },
-    });
+    ];
   };
 
-  const makeBulkUpdateTest = (describeFn: DescribeFn) => (
+  const makeBulkUpdateTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: BulkUpdateTestDefinition
+    definition: BulkUpdateTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, otherSpaceId, tests } = definition;
-
-    // We add this type into all bulk updates
-    // to ensure that having additional items in the bulk
-    // update doesn't change the expected outcome overall
-    let updateCount = 0;
-    const generateNonSpaceAwareGlobalSavedObject = () => ({
-      type: 'globaltype',
-      id: `8121a00-8efd-21e7-1cb3-34ab966434445`,
-      attributes: {
-        name: `Update #${++updateCount}`,
-      },
-    });
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
-      it(`should return ${tests.spaceAware.statusCode} for a space-aware doc`, async () => {
-        await supertest
-          .put(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_update`)
-          .auth(user.username, user.password)
-          .send([
-            generateNonSpaceAwareGlobalSavedObject(),
-            {
-              type: 'visualization',
-              id: `${getIdPrefix(otherSpaceId || spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-              attributes: {
-                title: 'My second favorite vis',
-              },
-            },
-            generateNonSpaceAwareGlobalSavedObject(),
-          ])
-          .expect(tests.spaceAware.statusCode)
-          .then(tests.spaceAware.response);
-      });
-
-      it(`should return ${tests.notSpaceAware.statusCode} for a non space-aware doc`, async () => {
-        await supertest
-          .put(`${getUrlPrefix(otherSpaceId || spaceId)}/api/saved_objects/_bulk_update`)
-          .auth(user.username, user.password)
-          .send([
-            generateNonSpaceAwareGlobalSavedObject(),
-            {
-              type: 'globaltype',
-              id: `8121a00-8efd-21e7-1cb3-34ab966434445`,
-              attributes: {
-                name: 'My second favorite',
-              },
-            },
-            generateNonSpaceAwareGlobalSavedObject(),
-          ])
-          .expect(tests.notSpaceAware.statusCode)
-          .then(tests.notSpaceAware.response);
-      });
 
-      it(`should return ${tests.hiddenType.statusCode} for hiddentype doc`, async () => {
-        await supertest
-          .put(`${getUrlPrefix(otherSpaceId || spaceId)}/api/saved_objects/_bulk_update`)
-          .auth(user.username, user.password)
-          .send([
-            generateNonSpaceAwareGlobalSavedObject(),
-            {
-              type: 'hiddentype',
-              id: 'hiddentype_1',
-              attributes: {
-                name: 'My favorite hidden type',
-              },
-            },
-            generateNonSpaceAwareGlobalSavedObject(),
-          ])
-          .expect(tests.hiddenType.statusCode)
-          .then(tests.hiddenType.response);
-      });
+      const attrs = { attributes: { [NEW_ATTRIBUTE_KEY]: NEW_ATTRIBUTE_VAL } };
 
-      describe('unknown id', () => {
-        it(`should return ${tests.doesntExist.statusCode}`, async () => {
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const requestBody = test.request.map(x => ({ ...x, ...attrs }));
           await supertest
             .put(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_update`)
-            .auth(user.username, user.password)
-            .send([
-              generateNonSpaceAwareGlobalSavedObject(),
-              {
-                type: 'visualization',
-                id: `${getIdPrefix(spaceId)}not an id`,
-                attributes: {
-                  title: 'My second favorite vis',
-                },
-              },
-              generateNonSpaceAwareGlobalSavedObject(),
-            ])
-            .expect(tests.doesntExist.statusCode)
-            .then(tests.doesntExist.response);
+            .auth(user?.username, user?.password)
+            .send(requestBody)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
+      }
     });
   };
 
-  const bulkUpdateTest = makeBulkUpdateTest(describe);
+  const addTests = makeBulkUpdateTest(describe);
   // @ts-ignore
-  bulkUpdateTest.only = makeBulkUpdateTest(describe.only);
+  addTests.only = makeBulkUpdateTest(describe.only);
 
   return {
-    createExpectDoesntExistNotFound,
-    createExpectSpaceAwareNotFound,
-    expectSpaceNotFound: expectHiddenTypeNotFound,
-    expectDoesntExistRbacForbidden,
-    expectNotSpaceAwareRbacForbidden,
-    expectNotSpaceAwareResults,
-    expectSpaceAwareRbacForbidden,
-    expectSpaceAwareResults,
-    expectHiddenTypeRbacForbidden,
-    expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-    bulkUpdateTest,
+    addTests,
+    createTestDefinitions,
+    expectForbidden,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/create.ts b/x-pack/test/saved_object_api_integration/common/suites/create.ts
index 29960c513d40f..f657756be92cd 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/create.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/create.ts
@@ -3,206 +3,117 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
+
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface CreateTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
-}
-
-interface CreateCustomTest extends CreateTest {
-  type: string;
-  description: string;
-  requestBody: any;
-}
-
-interface CreateTests {
-  spaceAware: CreateTest;
-  notSpaceAware: CreateTest;
-  hiddenType: CreateTest;
-  custom?: CreateCustomTest;
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface CreateTestDefinition extends TestDefinition {
+  request: { type: string; id: string };
+  overwrite: boolean;
 }
-
-interface CreateTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  tests: CreateTests;
+export type CreateTestSuite = TestSuite<CreateTestDefinition>;
+export interface CreateTestCase extends TestCase {
+  failure?: 400 | 403 | 409;
 }
 
-const spaceAwareType = 'visualization';
-const notSpaceAwareType = 'globaltype';
+const NEW_ATTRIBUTE_KEY = 'title'; // all type mappings include this attribute, for simplicity's sake
+const NEW_ATTRIBUTE_VAL = `New attribute value ${Date.now()}`;
+
+// ID intentionally left blank on NEW_SINGLE_NAMESPACE_OBJ to ensure we can create saved objects without specifying the ID
+// we could create six separate test cases to test every permutation, but there's no real value in doing so
+const NEW_SINGLE_NAMESPACE_OBJ = Object.freeze({ type: 'dashboard', id: '' });
+const NEW_MULTI_NAMESPACE_OBJ = Object.freeze({ type: 'sharedtype', id: 'new-sharedtype-id' });
+const NEW_NAMESPACE_AGNOSTIC_OBJ = Object.freeze({ type: 'globaltype', id: 'new-globaltype-id' });
+export const TEST_CASES = Object.freeze({
+  ...CASES,
+  NEW_SINGLE_NAMESPACE_OBJ,
+  NEW_MULTI_NAMESPACE_OBJ,
+  NEW_NAMESPACE_AGNOSTIC_OBJ,
+});
 
 export function createTestSuiteFactory(es: any, esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectRbacForbidden = (type: string) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to create ${type}`,
-    });
-  };
-
-  const expectBadRequestForHiddenType = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      message: "Unsupported saved object type: 'hiddentype': Bad Request",
-      statusCode: 400,
-      error: 'Bad Request',
-    });
-  };
-
-  const createExpectSpaceAwareResults = (spaceId = DEFAULT_SPACE_ID) => async (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body)
-      .to.have.property('id')
-      .match(/^[0-9a-f-]{36}$/);
-
-    // loose ISO8601 UTC time with milliseconds validation
-    expect(resp.body)
-      .to.have.property('updated_at')
-      .match(/^[\d-]{10}T[\d:\.]{12}Z$/);
-
-    expect(resp.body).to.eql({
-      id: resp.body.id,
-      migrationVersion: resp.body.migrationVersion,
-      type: spaceAwareType,
-      updated_at: resp.body.updated_at,
-      version: resp.body.version,
-      attributes: {
-        title: 'My favorite vis',
-      },
-      references: [],
-    });
-
-    const expectedSpacePrefix = spaceId === DEFAULT_SPACE_ID ? '' : `${spaceId}:`;
-
-    // query ES directory to ensure namespace was or wasn't specified
-    const { _source } = await es.get({
-      id: `${expectedSpacePrefix}${spaceAwareType}:${resp.body.id}`,
-      index: '.kibana',
-    });
-
-    const { namespace: actualNamespace } = _source;
-
-    if (spaceId === DEFAULT_SPACE_ID) {
-      expect(actualNamespace).to.eql(undefined);
+  const expectForbidden = expectResponses.forbidden('create');
+  const expectResponseBody = (
+    testCase: CreateTestCase,
+    spaceId = SPACES.DEFAULT.spaceId
+  ): ExpectResponseBody => async (response: Record<string, any>) => {
+    if (testCase.failure === 403) {
+      await expectForbidden(testCase.type)(response);
     } else {
-      expect(actualNamespace).to.eql(spaceId);
+      // permitted
+      const object = response.body;
+      await expectResponses.permitted(object, testCase);
+      if (!testCase.failure) {
+        expect(object.attributes[NEW_ATTRIBUTE_KEY]).to.eql(NEW_ATTRIBUTE_VAL);
+        await expectResponses.successCreated(es, spaceId, object.type, object.id);
+      }
     }
   };
-
-  const expectNotSpaceAwareRbacForbidden = createExpectRbacForbidden(notSpaceAwareType);
-
-  const expectNotSpaceAwareResults = async (resp: { [key: string]: any }) => {
-    expect(resp.body)
-      .to.have.property('id')
-      .match(/^[0-9a-f-]{36}$/);
-
-    // loose ISO8601 UTC time with milliseconds validation
-    expect(resp.body)
-      .to.have.property('updated_at')
-      .match(/^[\d-]{10}T[\d:\.]{12}Z$/);
-
-    expect(resp.body).to.eql({
-      id: resp.body.id,
-      type: notSpaceAwareType,
-      updated_at: resp.body.updated_at,
-      version: resp.body.version,
-      attributes: {
-        name: `Can't be contained to a space`,
-      },
-      references: [],
-    });
-
-    // query ES directory to ensure namespace wasn't specified
-    const { _source } = await es.get({
-      id: `${notSpaceAwareType}:${resp.body.id}`,
-      index: '.kibana',
-    });
-
-    const { namespace: actualNamespace } = _source;
-
-    expect(actualNamespace).to.eql(undefined);
+  const createTestDefinitions = (
+    testCases: CreateTestCase | CreateTestCase[],
+    forbidden: boolean,
+    overwrite: boolean,
+    options?: {
+      spaceId?: string;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): CreateTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 200,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x, options?.spaceId),
+      overwrite,
+    }));
   };
 
-  const expectSpaceAwareRbacForbidden = createExpectRbacForbidden(spaceAwareType);
-
-  const expectHiddenTypeRbacForbidden = createExpectRbacForbidden('hiddentype');
-
-  const makeCreateTest = (describeFn: DescribeFn) => (
+  const makeCreateTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: CreateTestDefinition
+    definition: CreateTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
+
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
-      it(`should return ${tests.spaceAware.statusCode} for a space-aware type`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/${spaceAwareType}`)
-          .auth(user.username, user.password)
-          .send({
-            attributes: {
-              title: 'My favorite vis',
-            },
-          })
-          .expect(tests.spaceAware.statusCode)
-          .then(tests.spaceAware.response);
-      });
-
-      it(`should return ${tests.notSpaceAware.statusCode} for a non space-aware type`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/${notSpaceAwareType}`)
-          .auth(user.username, user.password)
-          .send({
-            attributes: {
-              name: `Can't be contained to a space`,
-            },
-          })
-          .expect(tests.notSpaceAware.statusCode)
-          .then(tests.notSpaceAware.response);
-      });
-
-      it(`should return ${tests.hiddenType.statusCode} for the hiddentype`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/hiddentype`)
-          .auth(user.username, user.password)
-          .send({
-            attributes: {
-              name: `Can't be created via the Saved Objects API`,
-            },
-          })
-          .expect(tests.hiddenType.statusCode)
-          .then(tests.hiddenType.response);
-      });
 
-      if (tests.custom) {
-        it(tests.custom.description, async () => {
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const { type, id } = test.request;
+          const path = `${type}${id ? `/${id}` : ''}`;
+          const requestBody = { attributes: { [NEW_ATTRIBUTE_KEY]: NEW_ATTRIBUTE_VAL } };
+          const query = test.overwrite ? '?overwrite=true' : '';
           await supertest
-            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/${tests.custom!.type}`)
-            .auth(user.username, user.password)
-            .send(tests.custom!.requestBody)
-            .expect(tests.custom!.statusCode)
-            .then(tests.custom!.response);
+            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/${path}${query}`)
+            .auth(user?.username, user?.password)
+            .send(requestBody)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
       }
     });
   };
 
-  const createTest = makeCreateTest(describe);
+  const addTests = makeCreateTest(describe);
   // @ts-ignore
-  createTest.only = makeCreateTest(describe.only);
+  addTests.only = makeCreateTest(describe.only);
 
   return {
-    createExpectSpaceAwareResults,
-    createTest,
-    expectNotSpaceAwareRbacForbidden,
-    expectNotSpaceAwareResults,
-    expectSpaceAwareRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectHiddenTypeRbacForbidden,
+    addTests,
+    createTestDefinitions,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/delete.ts b/x-pack/test/saved_object_api_integration/common/suites/delete.ts
index d96ae5446d732..2222aa0c97267 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/delete.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/delete.ts
@@ -4,147 +4,97 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface DeleteTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
+import expect from '@kbn/expect/expect.js';
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface DeleteTestDefinition extends TestDefinition {
+  request: { type: string; id: string };
 }
-
-interface DeleteTests {
-  spaceAware: DeleteTest;
-  notSpaceAware: DeleteTest;
-  hiddenType: DeleteTest;
-  invalidId: DeleteTest;
+export type DeleteTestSuite = TestSuite<DeleteTestDefinition>;
+export interface DeleteTestCase extends TestCase {
+  failure?: 403 | 404;
 }
 
-interface DeleteTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  otherSpaceId?: string;
-  tests: DeleteTests;
-}
+const DOES_NOT_EXIST = Object.freeze({ type: 'dashboard', id: 'does-not-exist' });
+export const TEST_CASES = Object.freeze({ ...CASES, DOES_NOT_EXIST });
 
 export function deleteTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectNotFound = (spaceId: string, type: string, id: string) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      statusCode: 404,
-      error: 'Not Found',
-      message: `Saved object [${type}/${getIdPrefix(spaceId)}${id}] not found`,
-    });
-  };
-
-  const createExpectRbacForbidden = (type: string) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to delete ${type}`,
-    });
-  };
-
-  const expectGenericNotFound = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 404,
-      error: 'Not Found',
-      message: `Not Found`,
-    });
-  };
-
-  const createExpectSpaceAwareNotFound = (spaceId: string = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    createExpectNotFound(spaceId, 'dashboard', 'be3733a0-9efe-11e7-acb3-3dab96693fab')(resp);
-  };
-
-  const createExpectUnknownDocNotFound = (spaceId: string = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    createExpectNotFound(spaceId, 'dashboard', `not-a-real-id`)(resp);
+  const expectForbidden = expectResponses.forbidden('delete');
+  const expectResponseBody = (testCase: DeleteTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    if (testCase.failure === 403) {
+      await expectForbidden(testCase.type)(response);
+    } else {
+      // permitted
+      const object = response.body;
+      if (testCase.failure) {
+        await expectResponses.permitted(object, testCase);
+      } else {
+        // the success response for `delete` is an empty object
+        expect(object).to.eql({});
+      }
+    }
   };
-
-  const expectEmpty = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({});
+  const createTestDefinitions = (
+    testCases: DeleteTestCase | DeleteTestCase[],
+    forbidden: boolean,
+    options?: {
+      spaceId?: string;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): DeleteTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 200,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
   };
 
-  const expectRbacInvalidIdForbidden = createExpectRbacForbidden('dashboard');
-
-  const expectRbacNotSpaceAwareForbidden = createExpectRbacForbidden('globaltype');
-
-  const expectRbacSpaceAwareForbidden = createExpectRbacForbidden('dashboard');
-
-  const expectRbacHiddenTypeForbidden = createExpectRbacForbidden('hiddentype');
-
-  const makeDeleteTest = (describeFn: DescribeFn) => (
+  const makeDeleteTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: DeleteTestDefinition
+    definition: DeleteTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, otherSpaceId, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`should return ${tests.spaceAware.statusCode} when deleting a space-aware doc`, async () =>
-        await supertest
-          .delete(
-            `${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${getIdPrefix(
-              otherSpaceId || spaceId
-            )}be3733a0-9efe-11e7-acb3-3dab96693fab`
-          )
-          .auth(user.username, user.password)
-          .expect(tests.spaceAware.statusCode)
-          .then(tests.spaceAware.response));
-
-      it(`should return ${tests.notSpaceAware.statusCode} when deleting a non-space-aware doc`, async () =>
-        await supertest
-          .delete(
-            `${getUrlPrefix(
-              spaceId
-            )}/api/saved_objects/globaltype/8121a00-8efd-21e7-1cb3-34ab966434445`
-          )
-          .auth(user.username, user.password)
-          .expect(tests.notSpaceAware.statusCode)
-          .then(tests.notSpaceAware.response));
-
-      it(`should return ${tests.hiddenType.statusCode} when deleting a hiddentype doc`, async () =>
-        await supertest
-          .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/hiddentype/hiddentype_1`)
-          .auth(user.username, user.password)
-          .expect(tests.hiddenType.statusCode)
-          .then(tests.hiddenType.response));
-
-      it(`should return ${tests.invalidId.statusCode} when deleting an unknown doc`, async () =>
-        await supertest
-          .delete(
-            `${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${getIdPrefix(
-              otherSpaceId || spaceId
-            )}not-a-real-id`
-          )
-          .auth(user.username, user.password)
-          .expect(tests.invalidId.statusCode)
-          .then(tests.invalidId.response));
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const { type, id } = test.request;
+          await supertest
+            .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/${type}/${id}`)
+            .auth(user?.username, user?.password)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
+        });
+      }
     });
   };
 
-  const deleteTest = makeDeleteTest(describe);
+  const addTests = makeDeleteTest(describe);
   // @ts-ignore
-  deleteTest.only = makeDeleteTest(describe.only);
+  addTests.only = makeDeleteTest(describe.only);
 
   return {
-    expectGenericNotFound,
-    createExpectSpaceAwareNotFound,
-    createExpectUnknownDocNotFound,
-    deleteTest,
-    expectEmpty,
-    expectRbacInvalidIdForbidden,
-    expectRbacNotSpaceAwareForbidden,
-    expectRbacSpaceAwareForbidden,
-    expectRbacHiddenTypeForbidden,
+    addTests,
+    createTestDefinitions,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/export.ts b/x-pack/test/saved_object_api_integration/common/suites/export.ts
index e6853096962ec..ddd43d42410ae 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/export.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/export.ts
@@ -5,164 +5,191 @@
  */
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import { expectResponses, getUrlPrefix } from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
 
-interface ExportTest {
-  statusCode: number;
-  description: string;
-  response: (resp: { [key: string]: any }) => void;
-}
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
 
-interface ExportTests {
-  spaceAwareType: ExportTest;
-  hiddenType: ExportTest;
-  noTypeOrObjects: ExportTest;
+export interface ExportTestDefinition extends TestDefinition {
+  request: ReturnType<typeof createRequest>;
 }
-
-interface ExportTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  tests: ExportTests;
+export type ExportTestSuite = TestSuite<ExportTestDefinition>;
+export interface ExportTestCase {
+  title: string;
+  type: string;
+  id?: string;
+  successResult?: TestCase | TestCase[];
+  failure?: 400 | 403;
 }
 
+export const getTestCases = (spaceId?: string) => ({
+  singleNamespaceObject: {
+    title: 'single-namespace object',
+    ...(spaceId === SPACE_1_ID
+      ? CASES.SINGLE_NAMESPACE_SPACE_1
+      : spaceId === SPACE_2_ID
+      ? CASES.SINGLE_NAMESPACE_SPACE_2
+      : CASES.SINGLE_NAMESPACE_DEFAULT_SPACE),
+  } as ExportTestCase,
+  singleNamespaceType: {
+    // this test explicitly ensures that single-namespace objects from other spaces are not returned
+    title: 'single-namespace type',
+    type: 'isolatedtype',
+    successResult:
+      spaceId === SPACE_1_ID
+        ? CASES.SINGLE_NAMESPACE_SPACE_1
+        : spaceId === SPACE_2_ID
+        ? CASES.SINGLE_NAMESPACE_SPACE_2
+        : CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+  } as ExportTestCase,
+  multiNamespaceObject: {
+    title: 'multi-namespace object',
+    ...(spaceId === SPACE_1_ID
+      ? CASES.MULTI_NAMESPACE_ONLY_SPACE_1
+      : spaceId === SPACE_2_ID
+      ? CASES.MULTI_NAMESPACE_ONLY_SPACE_2
+      : CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1),
+    failure: 400, // multi-namespace types cannot be exported yet
+  } as ExportTestCase,
+  multiNamespaceType: {
+    title: 'multi-namespace type',
+    type: 'sharedtype',
+    // successResult:
+    //   spaceId === SPACE_1_ID
+    //     ? [CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, CASES.MULTI_NAMESPACE_ONLY_SPACE_1]
+    //     : spaceId === SPACE_2_ID
+    //     ? CASES.MULTI_NAMESPACE_ONLY_SPACE_2
+    //     : CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    failure: 400, // multi-namespace types cannot be exported yet
+  } as ExportTestCase,
+  namespaceAgnosticObject: {
+    title: 'namespace-agnostic object',
+    ...CASES.NAMESPACE_AGNOSTIC,
+  } as ExportTestCase,
+  namespaceAgnosticType: {
+    title: 'namespace-agnostic type',
+    type: 'globaltype',
+    successResult: CASES.NAMESPACE_AGNOSTIC,
+  } as ExportTestCase,
+  hiddenObject: { title: 'hidden object', ...CASES.HIDDEN, failure: 400 } as ExportTestCase,
+  hiddenType: { title: 'hidden type', type: 'hiddentype', failure: 400 } as ExportTestCase,
+});
+export const createRequest = ({ type, id }: ExportTestCase) =>
+  id ? { objects: [{ type, id }] } : { type };
+const getTestTitle = ({ failure, title }: ExportTestCase) => {
+  let description = 'success';
+  if (failure === 400) {
+    description = 'bad request';
+  } else if (failure === 403) {
+    description = 'forbidden';
+  }
+  return `${description} ["${title}"]`;
+};
+
 export function exportTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectRbacForbidden = (type: string) => (resp: { [key: string]: any }) => {
-    // In export only, the API uses "bulk_get" or "find" depending on the parameters it receives.
-    // The best that could be done here is to have an if statement to ensure at least one of the
-    // two errors has been thrown.
-    if (resp.body.message.indexOf(`bulk_get`) !== -1) {
-      expect(resp.body).to.eql({
-        statusCode: 403,
-        error: 'Forbidden',
-        message: `Unable to bulk_get ${type}`,
+  const expectForbiddenBulkGet = expectResponses.forbidden('bulk_get');
+  const expectForbiddenFind = expectResponses.forbidden('find');
+  const expectResponseBody = (testCase: ExportTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    const { type, id, successResult = { type, id }, failure } = testCase;
+    if (failure === 403) {
+      // In export only, the API uses "bulk_get" or "find" depending on the parameters it receives.
+      // The best that could be done here is to have an if statement to ensure at least one of the
+      // two errors has been thrown.
+      if (id) {
+        await expectForbiddenBulkGet(type)(response);
+      } else {
+        await expectForbiddenFind(type)(response);
+      }
+    } else if (failure === 400) {
+      // 400
+      expect(response.body.error).to.eql('Bad Request');
+      expect(response.body.statusCode).to.eql(failure);
+      if (id) {
+        expect(response.body.message).to.eql(
+          `Trying to export object(s) with non-exportable types: ${type}:${id}`
+        );
+      } else {
+        expect(response.body.message).to.eql(`Trying to export non-exportable type(s): ${type}`);
+      }
+    } else {
+      // 2xx
+      expect(response.body).not.to.have.property('error');
+      const ndjson = response.text.split('\n');
+      const savedObjectsArray = Array.isArray(successResult) ? successResult : [successResult];
+      expect(ndjson.length).to.eql(savedObjectsArray.length + 1);
+      for (let i = 0; i < savedObjectsArray.length; i++) {
+        const object = JSON.parse(ndjson[i]);
+        const { type: expectedType, id: expectedId } = savedObjectsArray[i];
+        expect(object.type).to.eql(expectedType);
+        expect(object.id).to.eql(expectedId);
+        expect(object.updated_at).to.match(/^[\d-]{10}T[\d:\.]{12}Z$/);
+        // don't test attributes, version, or references
+      }
+      const exportDetails = JSON.parse(ndjson[ndjson.length - 1]);
+      expect(exportDetails).to.eql({
+        exportedCount: ndjson.length - 1,
+        missingRefCount: 0,
+        missingReferences: [],
       });
-      return;
     }
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to find ${type}`,
-    });
   };
-
-  const expectTypeOrObjectsRequired = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 400,
-      error: 'Bad Request',
-      message: '[request body]: expected a plain object value, but found [null] instead.',
-    });
-  };
-
-  const expectInvalidTypeSpecified = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 400,
-      error: 'Bad Request',
-      message: `Trying to export object(s) with non-exportable types: hiddentype:hiddentype_1`,
-    });
-  };
-
-  const createExpectVisualizationResults = (spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    const response = JSON.parse(resp.text);
-    expect(response).to.eql({
-      type: 'visualization',
-      id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-      version: response.version,
-      attributes: response.attributes,
-      references: [
-        {
-          name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
-          type: 'index-pattern',
-          id: `${getIdPrefix(spaceId)}91200a00-9efd-11e7-acb3-3dab96693fab`,
-        },
-      ],
-      migrationVersion: response.migrationVersion,
-      updated_at: '2017-09-21T18:51:23.794Z',
-    });
+  const createTestDefinitions = (
+    testCases: ExportTestCase | ExportTestCase[],
+    forbidden: boolean,
+    options?: {
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): ExportTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 200,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
   };
 
-  const makeExportTest = (describeFn: DescribeFn) => (
+  const makeExportTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: ExportTestDefinition
+    definition: ExportTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, tests } = definition;
+    const { user, spaceId = DEFAULT_SPACE_ID, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`space aware type should return ${tests.spaceAwareType.statusCode} with ${tests.spaceAwareType.description} when querying by type`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_export`)
-          .send({
-            type: 'visualization',
-            excludeExportDetails: true,
-          })
-          .auth(user.username, user.password)
-          .expect(tests.spaceAwareType.statusCode)
-          .then(tests.spaceAwareType.response);
-      });
-
-      it(`space aware type should return ${tests.spaceAwareType.statusCode} with ${tests.spaceAwareType.description} when querying by objects`, async () => {
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_export`)
-          .send({
-            objects: [
-              {
-                type: 'visualization',
-                id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-              },
-            ],
-            excludeExportDetails: true,
-          })
-          .auth(user.username, user.password)
-          .expect(tests.spaceAwareType.statusCode)
-          .then(tests.spaceAwareType.response);
-      });
-
-      describe('hidden type', () => {
-        it(`should return ${tests.hiddenType.statusCode} with ${tests.hiddenType.description}`, async () => {
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
           await supertest
             .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_export`)
-            .send({
-              objects: [
-                {
-                  type: 'hiddentype',
-                  id: `hiddentype_1`,
-                },
-              ],
-              excludeExportDetails: true,
-            })
-            .auth(user.username, user.password)
-            .expect(tests.hiddenType.statusCode)
-            .then(tests.hiddenType.response);
+            .auth(user?.username, user?.password)
+            .send(test.request)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
-
-      describe('no type or objects', () => {
-        it(`should return ${tests.noTypeOrObjects.statusCode} with ${tests.noTypeOrObjects.description}`, async () => {
-          await supertest
-            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_export`)
-            .auth(user.username, user.password)
-            .expect(tests.noTypeOrObjects.statusCode)
-            .then(tests.noTypeOrObjects.response);
-        });
-      });
+      }
     });
   };
 
-  const exportTest = makeExportTest(describe);
+  const addTests = makeExportTest(describe);
   // @ts-ignore
-  exportTest.only = makeExportTest(describe.only);
+  addTests.only = makeExportTest(describe.only);
 
   return {
-    createExpectRbacForbidden,
-    expectTypeOrObjectsRequired,
-    expectInvalidTypeSpecified,
-    createExpectVisualizationResults,
-    exportTest,
+    addTests,
+    createTestDefinitions,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/find.ts b/x-pack/test/saved_object_api_integration/common/suites/find.ts
index 5479960634ccb..75d6653365fdf 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/find.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/find.ts
@@ -3,271 +3,190 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
+
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface FindTest {
-  statusCode: number;
-  description: string;
-  response: (resp: { [key: string]: any }) => void;
+import querystring from 'querystring';
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import { expectResponses, getUrlPrefix } from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+
+export interface FindTestDefinition extends TestDefinition {
+  request: { query: string };
 }
-
-interface FindTests {
-  spaceAwareType: FindTest;
-  notSpaceAwareType: FindTest;
-  unknownType: FindTest;
-  pageBeyondTotal: FindTest;
-  unknownSearchField: FindTest;
-  hiddenType: FindTest;
-  noType: FindTest;
-  filterWithNotSpaceAwareType: FindTest;
-  filterWithHiddenType: FindTest;
-  filterWithUnknownType: FindTest;
-  filterWithNoType: FindTest;
-  filterWithUnAllowedType: FindTest;
+export type FindTestSuite = TestSuite<FindTestDefinition>;
+export interface FindTestCase {
+  title: string;
+  query: string;
+  successResult?: {
+    savedObjects?: TestCase | TestCase[];
+    page?: number;
+    perPage?: number;
+    total?: number;
+  };
+  failure?: 400 | 403;
 }
 
-interface FindTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  tests: FindTests;
-}
+export const getTestCases = (spaceId?: string) => ({
+  singleNamespaceType: {
+    title: 'find single-namespace type',
+    query: 'type=isolatedtype&fields=title',
+    successResult: {
+      savedObjects:
+        spaceId === SPACE_1_ID
+          ? CASES.SINGLE_NAMESPACE_SPACE_1
+          : spaceId === SPACE_2_ID
+          ? CASES.SINGLE_NAMESPACE_SPACE_2
+          : CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    },
+  } as FindTestCase,
+  multiNamespaceType: {
+    title: 'find multi-namespace type',
+    query: 'type=sharedtype&fields=title',
+    successResult: {
+      savedObjects:
+        spaceId === SPACE_1_ID
+          ? [CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, CASES.MULTI_NAMESPACE_ONLY_SPACE_1]
+          : spaceId === SPACE_2_ID
+          ? CASES.MULTI_NAMESPACE_ONLY_SPACE_2
+          : CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    },
+  } as FindTestCase,
+  namespaceAgnosticType: {
+    title: 'find namespace-agnostic type',
+    query: 'type=globaltype&fields=title',
+    successResult: { savedObjects: CASES.NAMESPACE_AGNOSTIC },
+  } as FindTestCase,
+  hiddenType: { title: 'find hidden type', query: 'type=hiddentype&fields=name' } as FindTestCase,
+  unknownType: { title: 'find unknown type', query: 'type=wigwags' } as FindTestCase,
+  pageBeyondTotal: {
+    title: 'find page beyond total',
+    query: 'type=isolatedtype&page=100&per_page=100',
+    successResult: { page: 100, perPage: 100, total: 1, savedObjects: [] },
+  } as FindTestCase,
+  unknownSearchField: {
+    title: 'find unknown search field',
+    query: 'type=url&search_fields=a',
+  } as FindTestCase,
+  filterWithNamespaceAgnosticType: {
+    title: 'filter with namespace-agnostic type',
+    query: 'type=globaltype&filter=globaltype.attributes.title:*global*',
+    successResult: { savedObjects: CASES.NAMESPACE_AGNOSTIC },
+  } as FindTestCase,
+  filterWithHiddenType: {
+    title: 'filter with hidden type',
+    query: `type=hiddentype&fields=name&filter=hiddentype.attributes.title:'hello'`,
+  } as FindTestCase,
+  filterWithUnknownType: {
+    title: 'filter with unknown type',
+    query: `type=wigwags&filter=wigwags.attributes.title:'unknown'`,
+  } as FindTestCase,
+  filterWithDisallowedType: {
+    title: 'filter with disallowed type',
+    query: `type=globaltype&filter=dashboard.title:'Requests'`,
+    failure: 400,
+  } as FindTestCase,
+});
+export const createRequest = ({ query }: FindTestCase) => ({ query });
+const getTestTitle = ({ failure, title }: FindTestCase) => {
+  let description = 'success';
+  if (failure === 400) {
+    description = 'bad request';
+  } else if (failure === 403) {
+    description = 'forbidden';
+  }
+  return `${description} ["${title}"]`;
+};
 
 export function findTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectEmpty = (page: number, perPage: number, total: number) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      page,
-      per_page: perPage,
-      total,
-      saved_objects: [],
-    });
-  };
-
-  const createExpectRbacForbidden = (type?: string) => (resp: { [key: string]: any }) => {
-    const message = type ? `Unable to find ${type}` : `Not authorized to find saved_object`;
-
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message,
-    });
-  };
-
-  const expectNotSpaceAwareResults = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      page: 1,
-      per_page: 20,
-      total: 1,
-      saved_objects: [
-        {
-          type: 'globaltype',
-          id: `8121a00-8efd-21e7-1cb3-34ab966434445`,
-          version: resp.body.saved_objects[0].version,
-          attributes: {
-            name: 'My favorite global object',
-          },
-          references: [],
-          updated_at: '2017-09-21T18:59:16.270Z',
-        },
-      ],
-    });
-  };
-
-  const expectFilterWrongTypeError = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      error: 'Bad Request',
-      message: 'This type dashboard is not allowed: Bad Request',
-      statusCode: 400,
-    });
-  };
-
-  const expectTypeRequired = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      error: 'Bad Request',
-      message: '[request query.type]: expected at least one defined value but got [undefined]',
-      statusCode: 400,
-    });
+  const expectForbidden = expectResponses.forbidden('find');
+  const expectResponseBody = (testCase: FindTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    const { failure, successResult = {}, query } = testCase;
+    const parsedQuery = querystring.parse(query);
+    if (failure === 403) {
+      const type = parsedQuery.type;
+      await expectForbidden(type)(response);
+    } else if (failure === 400) {
+      const type = (parsedQuery.filter as string).split('.')[0];
+      expect(response.body.error).to.eql('Bad Request');
+      expect(response.body.statusCode).to.eql(failure);
+      expect(response.body.message).to.eql(`This type ${type} is not allowed: Bad Request`);
+    } else {
+      // 2xx
+      expect(response.body).not.to.have.property('error');
+      const { page = 1, perPage = 20, total, savedObjects = [] } = successResult;
+      const savedObjectsArray = Array.isArray(savedObjects) ? savedObjects : [savedObjects];
+      expect(response.body.page).to.eql(page);
+      expect(response.body.per_page).to.eql(perPage);
+      expect(response.body.total).to.eql(total || savedObjectsArray.length);
+      for (let i = 0; i < savedObjectsArray.length; i++) {
+        const object = response.body.saved_objects[i];
+        const { type: expectedType, id: expectedId } = savedObjectsArray[i];
+        expect(object.type).to.eql(expectedType);
+        expect(object.id).to.eql(expectedId);
+        expect(object.updated_at).to.match(/^[\d-]{10}T[\d:\.]{12}Z$/);
+        // don't test attributes, version, or references
+      }
+    }
   };
-
-  const createExpectVisualizationResults = (spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      page: 1,
-      per_page: 20,
-      total: 1,
-      saved_objects: [
-        {
-          type: 'visualization',
-          id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-          version: resp.body.saved_objects[0].version,
-          attributes: {
-            title: 'Count of requests',
-          },
-          migrationVersion: resp.body.saved_objects[0].migrationVersion,
-          references: [
-            {
-              id: `${getIdPrefix(spaceId)}91200a00-9efd-11e7-acb3-3dab96693fab`,
-              name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
-              type: 'index-pattern',
-            },
-          ],
-          updated_at: '2017-09-21T18:51:23.794Z',
-        },
-      ],
-    });
+  const createTestDefinitions = (
+    testCases: FindTestCase | FindTestCase[],
+    forbidden: boolean,
+    options?: {
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): FindTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 200,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
   };
 
-  const makeFindTest = (describeFn: DescribeFn) => (
+  const makeFindTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: FindTestDefinition
+    definition: FindTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, tests } = definition;
+    const { user, spaceId = DEFAULT_SPACE_ID, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`space aware type should return ${tests.spaceAwareType.statusCode} with ${tests.spaceAwareType.description}`, async () =>
-        await supertest
-          .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=visualization&fields=title`)
-          .auth(user.username, user.password)
-          .expect(tests.spaceAwareType.statusCode)
-          .then(tests.spaceAwareType.response));
-
-      it(`not space aware type should return ${tests.notSpaceAwareType.statusCode} with ${tests.notSpaceAwareType.description}`, async () =>
-        await supertest
-          .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=globaltype&fields=name`)
-          .auth(user.username, user.password)
-          .expect(tests.notSpaceAwareType.statusCode)
-          .then(tests.notSpaceAwareType.response));
-
-      it(`finding a hiddentype should return ${tests.hiddenType.statusCode} with ${tests.hiddenType.description}`, async () =>
-        await supertest
-          .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=hiddentype&fields=name`)
-          .auth(user.username, user.password)
-          .expect(tests.hiddenType.statusCode)
-          .then(tests.hiddenType.response));
-
-      describe('unknown type', () => {
-        it(`should return ${tests.unknownType.statusCode} with ${tests.unknownType.description}`, async () =>
-          await supertest
-            .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=wigwags`)
-            .auth(user.username, user.password)
-            .expect(tests.unknownType.statusCode)
-            .then(tests.unknownType.response));
-      });
-
-      describe('page beyond total', () => {
-        it(`should return ${tests.pageBeyondTotal.statusCode} with ${tests.pageBeyondTotal.description}`, async () =>
-          await supertest
-            .get(
-              `${getUrlPrefix(
-                spaceId
-              )}/api/saved_objects/_find?type=visualization&page=100&per_page=100`
-            )
-            .auth(user.username, user.password)
-            .expect(tests.pageBeyondTotal.statusCode)
-            .then(tests.pageBeyondTotal.response));
-      });
-
-      describe('unknown search field', () => {
-        it(`should return ${tests.unknownSearchField.statusCode} with ${tests.unknownSearchField.description}`, async () =>
-          await supertest
-            .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=url&search_fields=a`)
-            .auth(user.username, user.password)
-            .expect(tests.unknownSearchField.statusCode)
-            .then(tests.unknownSearchField.response));
-      });
-
-      describe('no type', () => {
-        it(`should return ${tests.noType.statusCode} with ${tests.noType.description}`, async () =>
-          await supertest
-            .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find`)
-            .auth(user.username, user.password)
-            .expect(tests.noType.statusCode)
-            .then(tests.noType.response));
-      });
-
-      describe('filter', () => {
-        it(`by wrong type should return ${tests.filterWithUnAllowedType.statusCode} with ${tests.filterWithUnAllowedType.description}`, async () =>
-          await supertest
-            .get(
-              `${getUrlPrefix(
-                spaceId
-              )}/api/saved_objects/_find?type=globaltype&filter=dashboard.title:'Requests'`
-            )
-            .auth(user.username, user.password)
-            .expect(tests.filterWithUnAllowedType.statusCode)
-            .then(tests.filterWithUnAllowedType.response));
-
-        it(`not space aware type should return ${tests.filterWithNotSpaceAwareType.statusCode} with ${tests.filterWithNotSpaceAwareType.description}`, async () =>
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const query = test.request.query ? `?${test.request.query}` : '';
           await supertest
-            .get(
-              `${getUrlPrefix(
-                spaceId
-              )}/api/saved_objects/_find?type=globaltype&filter=globaltype.attributes.name:*global*`
-            )
-            .auth(user.username, user.password)
-            .expect(tests.filterWithNotSpaceAwareType.statusCode)
-            .then(tests.filterWithNotSpaceAwareType.response));
-
-        it(`finding a hiddentype should return ${tests.filterWithHiddenType.statusCode} with ${tests.filterWithHiddenType.description}`, async () =>
-          await supertest
-            .get(
-              `${getUrlPrefix(
-                spaceId
-              )}/api/saved_objects/_find?type=hiddentype&fields=name&filter=hiddentype.attributes.name:'hello'`
-            )
-            .auth(user.username, user.password)
-            .expect(tests.filterWithHiddenType.statusCode)
-            .then(tests.filterWithHiddenType.response));
-
-        describe('unknown type', () => {
-          it(`should return ${tests.filterWithUnknownType.statusCode} with ${tests.filterWithUnknownType.description}`, async () =>
-            await supertest
-              .get(
-                `${getUrlPrefix(
-                  spaceId
-                )}/api/saved_objects/_find?type=wigwags&filter=wigwags.attributes.title:'unknown'`
-              )
-              .auth(user.username, user.password)
-              .expect(tests.filterWithUnknownType.statusCode)
-              .then(tests.filterWithUnknownType.response));
-        });
-
-        describe('no type', () => {
-          it(`should return ${tests.filterWithNoType.statusCode} with ${tests.filterWithNoType.description}`, async () =>
-            await supertest
-              .get(
-                `${getUrlPrefix(
-                  spaceId
-                )}/api/saved_objects/_find?filter=global.attributes.name:*global*`
-              )
-              .auth(user.username, user.password)
-              .expect(tests.filterWithNoType.statusCode)
-              .then(tests.filterWithNoType.response));
+            .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find${query}`)
+            .auth(user?.username, user?.password)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
+      }
     });
   };
 
-  const findTest = makeFindTest(describe);
+  const addTests = makeFindTest(describe);
   // @ts-ignore
-  findTest.only = makeFindTest(describe.only);
+  addTests.only = makeFindTest(describe.only);
 
   return {
-    createExpectEmpty,
-    createExpectRbacForbidden,
-    createExpectVisualizationResults,
-    expectFilterWrongTypeError,
-    expectNotSpaceAwareResults,
-    expectTypeRequired,
-    findTest,
+    addTests,
+    createTestDefinitions,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/get.ts b/x-pack/test/saved_object_api_integration/common/suites/get.ts
index c98209ca1e105..d8fa4d91276d7 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/get.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/get.ts
@@ -3,193 +3,89 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface GetTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
-}
-
-interface GetTests {
-  spaceAware: GetTest;
-  notSpaceAware: GetTest;
-  hiddenType: GetTest;
-  doesntExist: GetTest;
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface GetTestDefinition extends TestDefinition {
+  request: { type: string; id: string };
 }
+export type GetTestSuite = TestSuite<GetTestDefinition>;
+export type GetTestCase = TestCase;
 
-interface GetTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  otherSpaceId?: string;
-  tests: GetTests;
-}
-
-const spaceAwareId = 'dd7caf20-9efd-11e7-acb3-3dab96693fab';
-const notSpaceAwareId = '8121a00-8efd-21e7-1cb3-34ab966434445';
-const doesntExistId = 'foobar';
+const DOES_NOT_EXIST = Object.freeze({ type: 'dashboard', id: 'does-not-exist' });
+export const TEST_CASES = Object.freeze({ ...CASES, DOES_NOT_EXIST });
 
 export function getTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectDoesntExistNotFound = (spaceId = DEFAULT_SPACE_ID) => {
-    return createExpectNotFound('visualization', doesntExistId, spaceId);
-  };
-
-  const createExpectNotFound = (type: string, id: string, spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      error: 'Not Found',
-      message: `Saved object [${type}/${getIdPrefix(spaceId)}${id}] not found`,
-      statusCode: 404,
-    });
-  };
-
-  const expectHiddenTypeNotFound = createExpectNotFound(
-    'hiddentype',
-    'hiddentype_1',
-    DEFAULT_SPACE_ID
-  );
-
-  const createExpectNotSpaceAwareRbacForbidden = () => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      error: 'Forbidden',
-      message: `Unable to get globaltype`,
-      statusCode: 403,
-    });
-  };
-
-  const createExpectNotSpaceAwareResults = (spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      id: `${notSpaceAwareId}`,
-      type: 'globaltype',
-      updated_at: '2017-09-21T18:59:16.270Z',
-      version: resp.body.version,
-      attributes: {
-        name: 'My favorite global object',
-      },
-      references: [],
-    });
-  };
-
-  const createExpectRbacForbidden = (type: string) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      error: 'Forbidden',
-      message: `Unable to get ${type}`,
-      statusCode: 403,
-    });
+  const expectForbidden = expectResponses.forbidden('get');
+  const expectResponseBody = (testCase: GetTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    if (testCase.failure === 403) {
+      await expectForbidden(testCase.type)(response);
+    } else {
+      // permitted
+      const object = response.body;
+      await expectResponses.permitted(object, testCase);
+    }
   };
-
-  const createExpectSpaceAwareNotFound = (spaceId = DEFAULT_SPACE_ID) => {
-    return createExpectNotFound('visualization', spaceAwareId, spaceId);
+  const createTestDefinitions = (
+    testCases: GetTestCase | GetTestCase[],
+    forbidden: boolean,
+    options?: {
+      spaceId?: string;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): GetTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 200,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
   };
 
-  const expectSpaceAwareRbacForbidden = createExpectRbacForbidden('visualization');
-  const expectNotSpaceAwareRbacForbidden = createExpectRbacForbidden('globaltype');
-  const expectHiddenTypeRbacForbidden = createExpectRbacForbidden('hiddentype');
-  const expectDoesntExistRbacForbidden = createExpectRbacForbidden('visualization');
-
-  const createExpectSpaceAwareResults = (spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`,
-      type: 'visualization',
-      migrationVersion: resp.body.migrationVersion,
-      updated_at: '2017-09-21T18:51:23.794Z',
-      version: resp.body.version,
-      attributes: {
-        title: 'Count of requests',
-        description: '',
-        version: 1,
-        // cheat for some of the more complex attributes
-        visState: resp.body.attributes.visState,
-        uiStateJSON: resp.body.attributes.uiStateJSON,
-        kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta,
-      },
-      references: [
-        {
-          name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
-          type: 'index-pattern',
-          id: `${getIdPrefix(spaceId)}91200a00-9efd-11e7-acb3-3dab96693fab`,
-        },
-      ],
-    });
-  };
-
-  const makeGetTest = (describeFn: DescribeFn) => (
+  const makeGetTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: GetTestDefinition
+    definition: GetTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, otherSpaceId, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`should return ${tests.spaceAware.statusCode} when getting a space aware doc`, async () => {
-        await supertest
-          .get(
-            `${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${getIdPrefix(
-              otherSpaceId || spaceId
-            )}${spaceAwareId}`
-          )
-          .auth(user.username, user.password)
-          .expect(tests.spaceAware.statusCode)
-          .then(tests.spaceAware.response);
-      });
-
-      it(`should return ${tests.notSpaceAware.statusCode} when getting a non-space-aware doc`, async () => {
-        await supertest
-          .get(`${getUrlPrefix(spaceId)}/api/saved_objects/globaltype/${notSpaceAwareId}`)
-          .auth(user.username, user.password)
-          .expect(tests.notSpaceAware.statusCode)
-          .then(tests.notSpaceAware.response);
-      });
-
-      it(`should return ${tests.hiddenType.statusCode} when getting a hiddentype doc`, async () => {
-        await supertest
-          .get(`${getUrlPrefix(spaceId)}/api/saved_objects/hiddentype/hiddentype_1`)
-          .auth(user.username, user.password)
-          .expect(tests.hiddenType.statusCode)
-          .then(tests.hiddenType.response);
-      });
-
-      describe('document does not exist', () => {
-        it(`should return ${tests.doesntExist.statusCode}`, async () => {
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const { type, id } = test.request;
           await supertest
-            .get(
-              `${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${getIdPrefix(
-                otherSpaceId || spaceId
-              )}${doesntExistId}`
-            )
-            .auth(user.username, user.password)
-            .expect(tests.doesntExist.statusCode)
-            .then(tests.doesntExist.response);
+            .get(`${getUrlPrefix(spaceId)}/api/saved_objects/${type}/${id}`)
+            .auth(user?.username, user?.password)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
+      }
     });
   };
 
-  const getTest = makeGetTest(describe);
+  const addTests = makeGetTest(describe);
   // @ts-ignore
-  getTest.only = makeGetTest(describe.only);
+  addTests.only = makeGetTest(describe.only);
 
   return {
-    createExpectDoesntExistNotFound,
-    createExpectNotSpaceAwareRbacForbidden,
-    createExpectNotSpaceAwareResults,
-    createExpectSpaceAwareNotFound,
-    createExpectSpaceAwareResults,
-    expectHiddenTypeNotFound,
-    expectSpaceAwareRbacForbidden,
-    expectNotSpaceAwareRbacForbidden,
-    expectDoesntExistRbacForbidden,
-    expectHiddenTypeRbacForbidden,
-    getTest,
+    addTests,
+    createTestDefinitions,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/import.ts b/x-pack/test/saved_object_api_integration/common/suites/import.ts
index f6723c912f82e..2f631221c6955 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/import.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/import.ts
@@ -6,195 +6,152 @@
 
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface ImportTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface ImportTestDefinition extends TestDefinition {
+  request: Array<{ type: string; id: string }>;
 }
-
-interface ImportTests {
-  default: ImportTest;
-  hiddenType: ImportTest;
-  unknownType: ImportTest;
+export type ImportTestSuite = TestSuite<ImportTestDefinition>;
+export interface ImportTestCase extends TestCase {
+  failure?: 400 | 409; // only used for permitted response case
 }
 
-interface ImportTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  tests: ImportTests;
-}
+const NEW_ATTRIBUTE_KEY = 'title'; // all type mappings include this attribute, for simplicity's sake
+const NEW_ATTRIBUTE_VAL = `New attribute value ${Date.now()}`;
 
-const createImportData = (spaceId: string) => [
-  {
-    type: 'dashboard',
-    id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-    attributes: {
-      title: 'A great new dashboard',
-    },
-  },
-  {
-    type: 'globaltype',
-    id: '05976c65-1145-4858-bbf0-d225cc78a06e',
-    attributes: {
-      name: 'A new globaltype object',
-    },
-  },
-];
+const NEW_SINGLE_NAMESPACE_OBJ = Object.freeze({ type: 'dashboard', id: 'new-dashboard-id' });
+const NEW_MULTI_NAMESPACE_OBJ = Object.freeze({ type: 'sharedtype', id: 'new-sharedtype-id' });
+const NEW_NAMESPACE_AGNOSTIC_OBJ = Object.freeze({ type: 'globaltype', id: 'new-globaltype-id' });
+export const TEST_CASES = Object.freeze({
+  ...CASES,
+  NEW_SINGLE_NAMESPACE_OBJ,
+  NEW_MULTI_NAMESPACE_OBJ,
+  NEW_NAMESPACE_AGNOSTIC_OBJ,
+});
 
 export function importTestSuiteFactory(es: any, esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectResults = (spaceId = DEFAULT_SPACE_ID) => async (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      success: true,
-      successCount: 2,
-    });
-  };
-
-  const expectResultsWithUnsupportedHiddenType = async (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      success: false,
-      successCount: 2,
-      errors: [
-        {
-          error: {
-            type: 'unsupported_type',
-          },
-          id: '1',
-          type: 'hiddentype',
-        },
-      ],
-    });
+  const expectForbidden = expectResponses.forbidden('bulk_create');
+  const expectResponseBody = (
+    testCases: ImportTestCase | ImportTestCase[],
+    statusCode: 200 | 403,
+    spaceId = SPACES.DEFAULT.spaceId
+  ): ExpectResponseBody => async (response: Record<string, any>) => {
+    const testCaseArray = Array.isArray(testCases) ? testCases : [testCases];
+    if (statusCode === 403) {
+      const types = testCaseArray.map(x => x.type);
+      await expectForbidden(types)(response);
+    } else {
+      // permitted
+      const { success, successCount, errors } = response.body;
+      const expectedSuccesses = testCaseArray.filter(x => !x.failure);
+      const expectedFailures = testCaseArray.filter(x => x.failure);
+      expect(success).to.eql(expectedFailures.length === 0);
+      expect(successCount).to.eql(expectedSuccesses.length);
+      if (expectedFailures.length) {
+        expect(errors).to.have.length(expectedFailures.length);
+      } else {
+        expect(response.body).not.to.have.property('errors');
+      }
+      for (let i = 0; i < expectedSuccesses.length; i++) {
+        const { type, id } = expectedSuccesses[i];
+        const { _source } = await expectResponses.successCreated(es, spaceId, type, id);
+        expect(_source[type][NEW_ATTRIBUTE_KEY]).to.eql(NEW_ATTRIBUTE_VAL);
+      }
+      for (let i = 0; i < expectedFailures.length; i++) {
+        const { type, id, failure } = expectedFailures[i];
+        // we don't know the order of the returned errors; search for each one
+        const object = (errors as Array<Record<string, unknown>>).find(
+          x => x.type === type && x.id === id
+        );
+        expect(object).not.to.be(undefined);
+        if (failure === 400) {
+          expect(object!.error).to.eql({ type: 'unsupported_type' });
+        } else {
+          // 409
+          expect(object!.error).to.eql({ type: 'conflict' });
+        }
+      }
+    }
   };
-
-  const expectUnknownTypeUnsupported = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      success: false,
-      successCount: 2,
-      errors: [
-        {
-          id: '1',
-          type: 'wigwags',
-          title: 'Wigwags title',
-          error: {
-            type: 'unsupported_type',
-          },
-        },
-      ],
-    });
+  const createTestDefinitions = (
+    testCases: ImportTestCase | ImportTestCase[],
+    forbidden: boolean,
+    options?: {
+      spaceId?: string;
+      singleRequest?: boolean;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): ImportTestDefinition[] => {
+    const cases = Array.isArray(testCases) ? testCases : [testCases];
+    const responseStatusCode = forbidden ? 403 : 200;
+    if (!options?.singleRequest) {
+      // if we are testing cases that should result in a forbidden response, we can do each case individually
+      // this ensures that multiple test cases of a single type will each result in a forbidden error
+      return cases.map(x => ({
+        title: getTestTitle(x, responseStatusCode),
+        request: [createRequest(x)],
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride ||
+          expectResponseBody(x, responseStatusCode, options?.spaceId),
+      }));
+    }
+    // batch into a single request to save time during test execution
+    return [
+      {
+        title: getTestTitle(cases, responseStatusCode),
+        request: cases.map(x => createRequest(x)),
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride ||
+          expectResponseBody(cases, responseStatusCode, options?.spaceId),
+      },
+    ];
   };
 
-  const expectHiddenTypeUnsupported = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      success: false,
-      successCount: 2,
-      errors: [
-        {
-          id: '1',
-          type: 'hiddentype',
-          error: {
-            type: 'unsupported_type',
-          },
-        },
-      ],
-    });
-  };
-
-  const expectRbacForbidden = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to bulk_create dashboard,globaltype`,
-    });
-  };
-
-  const makeImportTest = (describeFn: DescribeFn) => (
+  const makeImportTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: ImportTestDefinition
+    definition: ImportTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`should return ${tests.default.statusCode}`, async () => {
-        const data = createImportData(spaceId);
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_import`)
-          .auth(user.username, user.password)
-          .attach(
-            'file',
-            Buffer.from(data.map(obj => JSON.stringify(obj)).join('\n'), 'utf8'),
-            'export.ndjson'
-          )
-          .expect(tests.default.statusCode)
-          .then(tests.default.response);
-      });
-
-      describe('hiddentype', () => {
-        it(`should return ${tests.hiddenType.statusCode}`, async () => {
-          const data = createImportData(spaceId);
-          data.push({
-            type: 'hiddentype',
-            id: '1',
-            attributes: {
-              name: 'My Hidden Type',
-            },
-          });
-          await supertest
-            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_import`)
-            .query({ overwrite: true })
-            .auth(user.username, user.password)
-            .attach(
-              'file',
-              Buffer.from(data.map(obj => JSON.stringify(obj)).join('\n'), 'utf8'),
-              'export.ndjson'
-            )
-            .expect(tests.hiddenType.statusCode)
-            .then(tests.hiddenType.response);
-        });
-      });
+      const attrs = { attributes: { [NEW_ATTRIBUTE_KEY]: NEW_ATTRIBUTE_VAL } };
 
-      describe('unknown type', () => {
-        it(`should return ${tests.unknownType.statusCode}`, async () => {
-          const data = createImportData(spaceId);
-          data.push({
-            type: 'wigwags',
-            id: '1',
-            attributes: {
-              title: 'Wigwags title',
-            },
-          });
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const requestBody = test.request
+            .map(obj => JSON.stringify({ ...obj, ...attrs }))
+            .join('\n');
           await supertest
             .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_import`)
-            .query({ overwrite: true })
-            .auth(user.username, user.password)
-            .attach(
-              'file',
-              Buffer.from(data.map(obj => JSON.stringify(obj)).join('\n'), 'utf8'),
-              'export.ndjson'
-            )
-            .expect(tests.unknownType.statusCode)
-            .then(tests.unknownType.response);
+            .auth(user?.username, user?.password)
+            .attach('file', Buffer.from(requestBody, 'utf8'), 'export.ndjson')
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
+      }
     });
   };
 
-  const importTest = makeImportTest(describe);
+  const addTests = makeImportTest(describe);
   // @ts-ignore
-  importTest.only = makeImportTest(describe.only);
+  addTests.only = makeImportTest(describe.only);
 
   return {
-    importTest,
-    createExpectResults,
-    expectResultsWithUnsupportedHiddenType,
-    expectRbacForbidden,
-    expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
+    addTests,
+    createTestDefinitions,
+    expectForbidden,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/common/suites/resolve_import_errors.ts
index 1b538b9b1b65d..47c4babc5fcf9 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/resolve_import_errors.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/resolve_import_errors.ts
@@ -6,219 +6,165 @@
 
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
 
-interface ResolveImportErrorsTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
+export interface ResolveImportErrorsTestDefinition extends TestDefinition {
+  request: Array<{ type: string; id: string }>;
+  overwrite: boolean;
 }
-
-interface ResolveImportErrorsTests {
-  default: ResolveImportErrorsTest;
-  hiddenType: ResolveImportErrorsTest;
-  unknownType: ResolveImportErrorsTest;
+export type ResolveImportErrorsTestSuite = TestSuite<ResolveImportErrorsTestDefinition>;
+export interface ResolveImportErrorsTestCase extends TestCase {
+  failure?: 400 | 409; // only used for permitted response case
 }
 
-interface ResolveImportErrorsTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  tests: ResolveImportErrorsTests;
-}
+const NEW_ATTRIBUTE_KEY = 'title'; // all type mappings include this attribute, for simplicity's sake
+const NEW_ATTRIBUTE_VAL = `New attribute value ${Date.now()}`;
 
-const createImportData = (spaceId: string) => [
-  {
-    type: 'dashboard',
-    id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-    attributes: {
-      title: 'A great new dashboard',
-    },
-  },
-  {
-    type: 'globaltype',
-    id: '05976c65-1145-4858-bbf0-d225cc78a06e',
-    attributes: {
-      name: 'A new globaltype object',
-    },
-  },
-];
+const NEW_SINGLE_NAMESPACE_OBJ = Object.freeze({ type: 'dashboard', id: 'new-dashboard-id' });
+const NEW_MULTI_NAMESPACE_OBJ = Object.freeze({ type: 'sharedtype', id: 'new-sharedtype-id' });
+const NEW_NAMESPACE_AGNOSTIC_OBJ = Object.freeze({ type: 'globaltype', id: 'new-globaltype-id' });
+export const TEST_CASES = Object.freeze({
+  ...CASES,
+  NEW_SINGLE_NAMESPACE_OBJ,
+  NEW_MULTI_NAMESPACE_OBJ,
+  NEW_NAMESPACE_AGNOSTIC_OBJ,
+});
 
 export function resolveImportErrorsTestSuiteFactory(
   es: any,
   esArchiver: any,
   supertest: SuperTest<any>
 ) {
-  const createExpectResults = (spaceId = DEFAULT_SPACE_ID) => async (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).to.eql({
-      success: true,
-      successCount: 1,
-    });
-  };
-
-  const expectUnknownTypeUnsupported = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      success: false,
-      successCount: 1,
-      errors: [
-        {
-          id: '1',
-          type: 'wigwags',
-          title: 'Wigwags title',
-          error: {
-            type: 'unsupported_type',
-          },
-        },
-      ],
-    });
-  };
-
-  const expectHiddenTypeUnsupported = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      success: false,
-      successCount: 1,
-      errors: [
-        {
-          id: '1',
-          type: 'hiddentype',
-          error: {
-            type: 'unsupported_type',
-          },
-        },
-      ],
-    });
+  const expectForbidden = expectResponses.forbidden('bulk_create');
+  const expectResponseBody = (
+    testCases: ResolveImportErrorsTestCase | ResolveImportErrorsTestCase[],
+    statusCode: 200 | 403,
+    spaceId = SPACES.DEFAULT.spaceId
+  ): ExpectResponseBody => async (response: Record<string, any>) => {
+    const testCaseArray = Array.isArray(testCases) ? testCases : [testCases];
+    if (statusCode === 403) {
+      const types = testCaseArray.map(x => x.type);
+      await expectForbidden(types)(response);
+    } else {
+      // permitted
+      const { success, successCount, errors } = response.body;
+      const expectedSuccesses = testCaseArray.filter(x => !x.failure);
+      const expectedFailures = testCaseArray.filter(x => x.failure);
+      expect(success).to.eql(expectedFailures.length === 0);
+      expect(successCount).to.eql(expectedSuccesses.length);
+      if (expectedFailures.length) {
+        expect(errors).to.have.length(expectedFailures.length);
+      } else {
+        expect(response.body).not.to.have.property('errors');
+      }
+      for (let i = 0; i < expectedSuccesses.length; i++) {
+        const { type, id } = expectedSuccesses[i];
+        const { _source } = await expectResponses.successCreated(es, spaceId, type, id);
+        expect(_source[type][NEW_ATTRIBUTE_KEY]).to.eql(NEW_ATTRIBUTE_VAL);
+      }
+      for (let i = 0; i < expectedFailures.length; i++) {
+        const { type, id, failure } = expectedFailures[i];
+        // we don't know the order of the returned errors; search for each one
+        const object = (errors as Array<Record<string, unknown>>).find(
+          x => x.type === type && x.id === id
+        );
+        expect(object).not.to.be(undefined);
+        if (failure === 400) {
+          expect(object!.error).to.eql({ type: 'unsupported_type' });
+        } else {
+          // 409
+          expect(object!.error).to.eql({ type: 'conflict' });
+        }
+      }
+    }
   };
-
-  const expectRbacForbidden = (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to bulk_create dashboard`,
-    });
+  const createTestDefinitions = (
+    testCases: ResolveImportErrorsTestCase | ResolveImportErrorsTestCase[],
+    forbidden: boolean,
+    overwrite: boolean,
+    options?: {
+      spaceId?: string;
+      singleRequest?: boolean;
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): ResolveImportErrorsTestDefinition[] => {
+    const cases = Array.isArray(testCases) ? testCases : [testCases];
+    const responseStatusCode = forbidden ? 403 : 200;
+    if (!options?.singleRequest) {
+      // if we are testing cases that should result in a forbidden response, we can do each case individually
+      // this ensures that multiple test cases of a single type will each result in a forbidden error
+      return cases.map(x => ({
+        title: getTestTitle(x, responseStatusCode),
+        request: [createRequest(x)],
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride ||
+          expectResponseBody(x, responseStatusCode, options?.spaceId),
+        overwrite,
+      }));
+    }
+    // batch into a single request to save time during test execution
+    return [
+      {
+        title: getTestTitle(cases, responseStatusCode),
+        request: cases.map(x => createRequest(x)),
+        responseStatusCode,
+        responseBody:
+          options?.responseBodyOverride ||
+          expectResponseBody(cases, responseStatusCode, options?.spaceId),
+        overwrite,
+      },
+    ];
   };
 
-  const makeResolveImportErrorsTest = (describeFn: DescribeFn) => (
+  const makeResolveImportErrorsTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: ResolveImportErrorsTestDefinition
+    definition: ResolveImportErrorsTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
 
-      it(`should return ${tests.default.statusCode}`, async () => {
-        const data = createImportData(spaceId);
-        await supertest
-          .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_resolve_import_errors`)
-          .auth(user.username, user.password)
-          .field(
-            'retries',
-            JSON.stringify([
-              {
-                type: 'dashboard',
-                id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-                overwrite: true,
-              },
-            ])
-          )
-          .attach(
-            'file',
-            Buffer.from(data.map(obj => JSON.stringify(obj)).join('\n'), 'utf8'),
-            'export.ndjson'
-          )
-          .expect(tests.default.statusCode)
-          .then(tests.default.response);
-      });
+      const attrs = { attributes: { [NEW_ATTRIBUTE_KEY]: NEW_ATTRIBUTE_VAL } };
 
-      describe('unknown type', () => {
-        it(`should return ${tests.unknownType.statusCode}`, async () => {
-          const data = createImportData(spaceId);
-          data.push({
-            type: 'wigwags',
-            id: '1',
-            attributes: {
-              title: 'Wigwags title',
-            },
-          });
-          await supertest
-            .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_resolve_import_errors`)
-            .auth(user.username, user.password)
-            .field(
-              'retries',
-              JSON.stringify([
-                {
-                  type: 'wigwags',
-                  id: '1',
-                  overwrite: true,
-                },
-                {
-                  type: 'dashboard',
-                  id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-                  overwrite: true,
-                },
-              ])
-            )
-            .attach(
-              'file',
-              Buffer.from(data.map(obj => JSON.stringify(obj)).join('\n'), 'utf8'),
-              'export.ndjson'
-            )
-            .expect(tests.unknownType.statusCode)
-            .then(tests.unknownType.response);
-        });
-      });
-      describe('hidden type', () => {
-        it(`should return ${tests.hiddenType.statusCode}`, async () => {
-          const data = createImportData(spaceId);
-          data.push({
-            type: 'hiddentype',
-            id: '1',
-            attributes: {
-              name: 'My Hidden Type',
-            },
-          });
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const retryAttrs = test.overwrite ? { overwrite: true } : {};
+          const retries = JSON.stringify(
+            test.request.map(({ type, id }) => ({ type, id, ...retryAttrs }))
+          );
+          const requestBody = test.request
+            .map(obj => JSON.stringify({ ...obj, ...attrs }))
+            .join('\n');
           await supertest
             .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_resolve_import_errors`)
-            .auth(user.username, user.password)
-            .field(
-              'retries',
-              JSON.stringify([
-                {
-                  type: 'hiddentype',
-                  id: '1',
-                  overwrite: true,
-                },
-                {
-                  type: 'dashboard',
-                  id: `${getIdPrefix(spaceId)}a01b2f57-fcfd-4864-b735-09e28f0d815e`,
-                  overwrite: true,
-                },
-              ])
-            )
-            .attach(
-              'file',
-              Buffer.from(data.map(obj => JSON.stringify(obj)).join('\n'), 'utf8'),
-              'export.ndjson'
-            )
-            .expect(tests.hiddenType.statusCode)
-            .then(tests.hiddenType.response);
+            .auth(user?.username, user?.password)
+            .field('retries', retries)
+            .attach('file', Buffer.from(requestBody, 'utf8'), 'export.ndjson')
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
+      }
     });
   };
 
-  const resolveImportErrorsTest = makeResolveImportErrorsTest(describe);
+  const addTests = makeResolveImportErrorsTest(describe);
   // @ts-ignore
-  resolveImportErrorsTest.only = makeResolveImportErrorsTest(describe.only);
+  addTests.only = makeResolveImportErrorsTest(describe.only);
 
   return {
-    resolveImportErrorsTest,
-    createExpectResults,
-    expectRbacForbidden,
-    expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
+    addTests,
+    createTestDefinitions,
+    expectForbidden,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/common/suites/update.ts b/x-pack/test/saved_object_api_integration/common/suites/update.ts
index d6b7602c0114a..587e8cf320a4f 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/update.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/update.ts
@@ -6,205 +6,97 @@
 
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
-import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants';
-import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils';
-import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
-
-interface UpdateTest {
-  statusCode: number;
-  response: (resp: { [key: string]: any }) => void;
-}
-
-interface UpdateTests {
-  spaceAware: UpdateTest;
-  notSpaceAware: UpdateTest;
-  hiddenType: UpdateTest;
-  doesntExist: UpdateTest;
+import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
+import { SPACES } from '../lib/spaces';
+import {
+  createRequest,
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../lib/saved_object_test_utils';
+import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types';
+
+export interface UpdateTestDefinition extends TestDefinition {
+  request: { type: string; id: string };
 }
-
-interface UpdateTestDefinition {
-  user?: TestDefinitionAuthentication;
-  spaceId?: string;
-  otherSpaceId?: string;
-  tests: UpdateTests;
+export type UpdateTestSuite = TestSuite<UpdateTestDefinition>;
+export interface UpdateTestCase extends TestCase {
+  failure?: 403 | 404;
 }
 
-export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
-  const createExpectNotFound = (type: string, id: string, spaceId = DEFAULT_SPACE_ID) => (resp: {
-    [key: string]: any;
-  }) => {
-    expect(resp.body).eql({
-      statusCode: 404,
-      error: 'Not Found',
-      message: `Saved object [${type}/${getIdPrefix(spaceId)}${id}] not found`,
-    });
-  };
-
-  const createExpectDoesntExistNotFound = (spaceId?: string) => {
-    return createExpectNotFound('visualization', 'not an id', spaceId);
-  };
-
-  const createExpectSpaceAwareNotFound = (spaceId?: string) => {
-    return createExpectNotFound('visualization', 'dd7caf20-9efd-11e7-acb3-3dab96693fab', spaceId);
-  };
-
-  const expectHiddenTypeNotFound = createExpectNotFound(
-    'hiddentype',
-    'hiddentype_1',
-    DEFAULT_SPACE_ID
-  );
-
-  const createExpectRbacForbidden = (type: string) => (resp: { [key: string]: any }) => {
-    expect(resp.body).to.eql({
-      statusCode: 403,
-      error: 'Forbidden',
-      message: `Unable to update ${type}`,
-    });
-  };
+const NEW_ATTRIBUTE_KEY = 'title'; // all type mappings include this attribute, for simplicity's sake
+const NEW_ATTRIBUTE_VAL = `Updated attribute value ${Date.now()}`;
 
-  const expectDoesntExistRbacForbidden = createExpectRbacForbidden('visualization');
+const DOES_NOT_EXIST = Object.freeze({ type: 'dashboard', id: 'does-not-exist' });
+export const TEST_CASES = Object.freeze({ ...CASES, DOES_NOT_EXIST });
 
-  const expectNotSpaceAwareRbacForbidden = createExpectRbacForbidden('globaltype');
-
-  const expectHiddenTypeRbacForbidden = createExpectRbacForbidden('hiddentype');
-
-  const expectNotSpaceAwareResults = (resp: { [key: string]: any }) => {
-    // loose uuid validation
-    expect(resp.body)
-      .to.have.property('id')
-      .match(/^[0-9a-f-]{36}$/);
-
-    // loose ISO8601 UTC time with milliseconds validation
-    expect(resp.body)
-      .to.have.property('updated_at')
-      .match(/^[\d-]{10}T[\d:\.]{12}Z$/);
-
-    expect(resp.body).to.eql({
-      id: resp.body.id,
-      type: 'globaltype',
-      updated_at: resp.body.updated_at,
-      version: resp.body.version,
-      attributes: {
-        name: 'My second favorite',
-      },
-    });
+export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
+  const expectForbidden = expectResponses.forbidden('update');
+  const expectResponseBody = (testCase: UpdateTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    if (testCase.failure === 403) {
+      await expectForbidden(testCase.type)(response);
+    } else {
+      // permitted
+      const object = response.body;
+      await expectResponses.permitted(object, testCase);
+      if (!testCase.failure) {
+        expect(object.attributes[NEW_ATTRIBUTE_KEY]).to.eql(NEW_ATTRIBUTE_VAL);
+      }
+    }
   };
-
-  const expectSpaceAwareRbacForbidden = createExpectRbacForbidden('visualization');
-
-  const expectSpaceAwareResults = (resp: { [key: string]: any }) => {
-    // loose uuid validation ignoring prefix
-    expect(resp.body)
-      .to.have.property('id')
-      .match(/[0-9a-f-]{36}$/);
-
-    // loose ISO8601 UTC time with milliseconds validation
-    expect(resp.body)
-      .to.have.property('updated_at')
-      .match(/^[\d-]{10}T[\d:\.]{12}Z$/);
-
-    expect(resp.body).to.eql({
-      id: resp.body.id,
-      type: 'visualization',
-      updated_at: resp.body.updated_at,
-      version: resp.body.version,
-      attributes: {
-        title: 'My second favorite vis',
-      },
-    });
+  const createTestDefinitions = (
+    testCases: UpdateTestCase | UpdateTestCase[],
+    forbidden: boolean,
+    options?: {
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): UpdateTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 200,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
   };
 
-  const makeUpdateTest = (describeFn: DescribeFn) => (
+  const makeUpdateTest = (describeFn: Mocha.SuiteFunction) => (
     description: string,
-    definition: UpdateTestDefinition
+    definition: UpdateTestSuite
   ) => {
-    const { user = {}, spaceId = DEFAULT_SPACE_ID, otherSpaceId, tests } = definition;
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
 
     describeFn(description, () => {
       before(() => esArchiver.load('saved_objects/spaces'));
       after(() => esArchiver.unload('saved_objects/spaces'));
-      it(`should return ${tests.spaceAware.statusCode} for a space-aware doc`, async () => {
-        await supertest
-          .put(
-            `${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${getIdPrefix(
-              otherSpaceId || spaceId
-            )}dd7caf20-9efd-11e7-acb3-3dab96693fab`
-          )
-          .auth(user.username, user.password)
-          .send({
-            attributes: {
-              title: 'My second favorite vis',
-            },
-          })
-          .expect(tests.spaceAware.statusCode)
-          .then(tests.spaceAware.response);
-      });
-
-      it(`should return ${tests.notSpaceAware.statusCode} for a non space-aware doc`, async () => {
-        await supertest
-          .put(
-            `${getUrlPrefix(
-              otherSpaceId || spaceId
-            )}/api/saved_objects/globaltype/8121a00-8efd-21e7-1cb3-34ab966434445`
-          )
-          .auth(user.username, user.password)
-          .send({
-            attributes: {
-              name: 'My second favorite',
-            },
-          })
-          .expect(tests.notSpaceAware.statusCode)
-          .then(tests.notSpaceAware.response);
-      });
-
-      it(`should return ${tests.hiddenType.statusCode} for hiddentype doc`, async () => {
-        await supertest
-          .put(`${getUrlPrefix(otherSpaceId || spaceId)}/api/saved_objects/hiddentype/hiddentype_1`)
-          .auth(user.username, user.password)
-          .send({
-            attributes: {
-              name: 'My favorite hidden type',
-            },
-          })
-          .expect(tests.hiddenType.statusCode)
-          .then(tests.hiddenType.response);
-      });
 
-      describe('unknown id', () => {
-        it(`should return ${tests.doesntExist.statusCode}`, async () => {
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const { type, id } = test.request;
+          const requestBody = { attributes: { [NEW_ATTRIBUTE_KEY]: NEW_ATTRIBUTE_VAL } };
           await supertest
-            .put(
-              `${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${getIdPrefix(
-                spaceId
-              )}not an id`
-            )
-            .auth(user.username, user.password)
-            .send({
-              attributes: {
-                title: 'My second favorite vis',
-              },
-            })
-            .expect(tests.doesntExist.statusCode)
-            .then(tests.doesntExist.response);
+            .put(`${getUrlPrefix(spaceId)}/api/saved_objects/${type}/${id}`)
+            .auth(user?.username, user?.password)
+            .send(requestBody)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
         });
-      });
+      }
     });
   };
 
-  const updateTest = makeUpdateTest(describe);
+  const addTests = makeUpdateTest(describe);
   // @ts-ignore
-  updateTest.only = makeUpdateTest(describe.only);
+  addTests.only = makeUpdateTest(describe.only);
 
   return {
-    createExpectDoesntExistNotFound,
-    createExpectSpaceAwareNotFound,
-    expectSpaceNotFound: expectHiddenTypeNotFound,
-    expectDoesntExistRbacForbidden,
-    expectNotSpaceAwareRbacForbidden,
-    expectNotSpaceAwareResults,
-    expectSpaceAwareRbacForbidden,
-    expectSpaceAwareResults,
-    expectHiddenTypeRbacForbidden,
-    updateTest,
+    addTests,
+    createTestDefinitions,
   };
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts
index 7768665f3b941..70d3afbfc9af3 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts
@@ -4,206 +4,104 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkCreateTestSuiteFactory } from '../../common/suites/bulk_create';
+import {
+  bulkCreateTestSuiteFactory,
+  TEST_CASES as CASES,
+  BulkCreateTestDefinition,
+} from '../../common/suites/bulk_create';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean, spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    {
+      ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+      ...fail409(!overwrite && spaceId === DEFAULT_SPACE_ID),
+    },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409(!overwrite || spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409(!overwrite || spaceId !== SPACE_2_ID) },
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_MULTI_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail400() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    bulkCreateTest,
-    createExpectResults,
-    createExpectRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectedForbiddenTypesWithHiddenType,
-  } = bulkCreateTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = bulkCreateTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = (overwrite: boolean, spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(overwrite, spaceId);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true, overwrite, { spaceId }),
+      authorized: [
+        createTestDefinitions(normalTypes, false, overwrite, { spaceId, singleRequest: true }),
+        createTestDefinitions(hiddenType, true, overwrite, { spaceId }),
+        createTestDefinitions(allTypes, true, overwrite, {
+          spaceId,
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['hiddentype']),
+        }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, overwrite, {
+        spaceId,
+        singleRequest: true,
+      }),
+    };
+  };
 
   describe('_bulk_create', () => {
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      bulkCreateTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-
-      bulkCreateTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingSpace: {
-            statusCode: 200,
-            response: expectBadRequestForHiddenType,
-          },
-        },
-      });
-
-      bulkCreateTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-
-      bulkCreateTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkCreateTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-
-      bulkCreateTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkCreateTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-
-      bulkCreateTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkCreateTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
+    getTestScenarios([false, true]).securityAndSpaces.forEach(
+      ({ spaceId, users, modifier: overwrite }) => {
+        const suffix = ` within the ${spaceId} space${overwrite ? ' with overwrite enabled' : ''}`;
+        const { unauthorized, authorized, superuser } = createTests(overwrite!, spaceId);
+        const _addTests = (user: TestUser, tests: BulkCreateTestDefinition[]) => {
+          addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+        };
 
-      bulkCreateTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingSpace: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-    });
+        [
+          users.noAccess,
+          users.legacyAll,
+          users.dualRead,
+          users.readGlobally,
+          users.readAtSpace,
+          users.allAtOtherSpace,
+        ].forEach(user => {
+          _addTests(user, unauthorized);
+        });
+        [users.dualAll, users.allGlobally, users.allAtSpace].forEach(user => {
+          _addTests(user, authorized);
+        });
+        _addTests(users.superuser, superuser);
+      }
+    );
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts
index ec5bce1707569..09ea867bff371 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts
@@ -4,205 +4,91 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkGetTestSuiteFactory } from '../../common/suites/bulk_get';
+import {
+  bulkGetTestSuiteFactory,
+  TEST_CASES as CASES,
+  BulkGetTestDefinition,
+} from '../../common/suites/bulk_get';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail400() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  const {
-    bulkGetTest,
-    createExpectResults,
-    createExpectRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectedForbiddenTypesWithHiddenType,
-  } = bulkGetTestSuiteFactory(esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = bulkGetTestSuiteFactory(
+    esArchiver,
+    supertest
+  );
+  const createTests = (spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(spaceId);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false, { singleRequest: true }),
+        createTestDefinitions(hiddenType, true),
+        createTestDefinitions(allTypes, true, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['hiddentype']),
+        }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, { singleRequest: true }),
+    };
+  };
 
   describe('_bulk_get', () => {
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      bulkGetTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-
-      bulkGetTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 200,
-            response: expectBadRequestForHiddenType,
-          },
-        },
-      });
-
-      bulkGetTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
-      });
-
-      bulkGetTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized, superuser } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: BulkGetTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      bulkGetTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
+      [users.noAccess, users.legacyAll, users.allAtOtherSpace].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      bulkGetTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkGetTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkGetTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkGetTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(['hiddentype']),
-          },
-        },
-      });
-
-      bulkGetTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(),
-          },
-          includingHiddenType: {
-            statusCode: 403,
-            response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-          },
-        },
+      [
+        users.dualAll,
+        users.dualRead,
+        users.allGlobally,
+        users.readGlobally,
+        users.allAtSpace,
+        users.readAtSpace,
+      ].forEach(user => {
+        _addTests(user, authorized);
       });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts
index 06240647b37a8..987209653b347 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts
@@ -4,290 +4,91 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkUpdateTestSuiteFactory } from '../../common/suites/bulk_update';
+import {
+  bulkUpdateTestSuiteFactory,
+  TEST_CASES as CASES,
+  BulkUpdateTestDefinition,
+} from '../../common/suites/bulk_update';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('bulkUpdate', () => {
-    const {
-      createExpectDoesntExistNotFound,
-      expectDoesntExistRbacForbidden,
-      expectNotSpaceAwareResults,
-      expectNotSpaceAwareRbacForbidden,
-      expectSpaceAwareRbacForbidden,
-      expectSpaceAwareResults,
-      expectSpaceNotFound,
-      expectHiddenTypeRbacForbidden,
-      expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-      bulkUpdateTest,
-    } = bulkUpdateTestSuiteFactory(esArchiver, supertest);
-
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      bulkUpdateTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      bulkUpdateTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectSpaceNotFound,
-          },
-          doesntExist: {
-            statusCode: 200,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      bulkUpdateTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      bulkUpdateTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-          },
-          doesntExist: {
-            statusCode: 200,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
+  const { addTests, createTestDefinitions, expectForbidden } = bulkUpdateTestSuiteFactory(
+    esArchiver,
+    supertest
+  );
+  const createTests = (spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(spaceId);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false, { singleRequest: true }),
+        createTestDefinitions(hiddenType, true),
+        createTestDefinitions(allTypes, true, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['hiddentype']),
+        }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, { singleRequest: true }),
+    };
+  };
 
-      bulkUpdateTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
+  describe('_bulk_update', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized, superuser } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: BulkUpdateTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      bulkUpdateTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-          },
-          doesntExist: {
-            statusCode: 200,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.readAtSpace,
+        users.allAtOtherSpace,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      bulkUpdateTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      bulkUpdateTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-          },
-          doesntExist: {
-            statusCode: 200,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      bulkUpdateTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      bulkUpdateTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
+      [users.dualAll, users.allGlobally, users.allAtSpace].forEach(user => {
+        _addTests(user, authorized);
       });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts
index e4adaa580c1db..7278504b8f0e8 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts
@@ -4,248 +4,91 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { createTestSuiteFactory } from '../../common/suites/create';
+import {
+  createTestSuiteFactory,
+  TEST_CASES as CASES,
+  CreateTestDefinition,
+} from '../../common/suites/create';
 
-export default function({ getService }: FtrProviderContext) {
-  const supertestWithoutAuth = getService('supertestWithoutAuth');
-  const es = getService('legacyEs');
-  const esArchiver = getService('esArchiver');
-
-  const {
-    createTest,
-    createExpectSpaceAwareResults,
-    expectNotSpaceAwareResults,
-    expectNotSpaceAwareRbacForbidden,
-    expectSpaceAwareRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectHiddenTypeRbacForbidden,
-  } = createTestSuiteFactory(es, esArchiver, supertestWithoutAuth);
-
-  describe('create', () => {
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      createTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
-
-      createTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 400,
-            response: expectBadRequestForHiddenType,
-          },
-        },
-      });
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
 
-      createTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
+const createTestCases = (overwrite: boolean, spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    {
+      ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+      ...fail409(!overwrite && spaceId === DEFAULT_SPACE_ID),
+    },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409(!overwrite || spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409(!overwrite || spaceId !== SPACE_2_ID) },
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_MULTI_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail400() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
-      createTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
-
-      createTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
-
-      createTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
-
-      createTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
+export default function({ getService }: FtrProviderContext) {
+  const supertest = getService('supertestWithoutAuth');
+  const esArchiver = getService('esArchiver');
+  const es = getService('legacyEs');
 
-      createTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
+  const { addTests, createTestDefinitions } = createTestSuiteFactory(es, esArchiver, supertest);
+  const createTests = (overwrite: boolean, spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(overwrite, spaceId);
+    return {
+      unauthorized: createTestDefinitions(allTypes, true, overwrite, { spaceId }),
+      authorized: [
+        createTestDefinitions(normalTypes, false, overwrite, { spaceId }),
+        createTestDefinitions(hiddenType, true, overwrite, { spaceId }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, overwrite, { spaceId }),
+    };
+  };
 
-      createTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
+  describe('_create', () => {
+    getTestScenarios([false, true]).securityAndSpaces.forEach(
+      ({ spaceId, users, modifier: overwrite }) => {
+        const suffix = ` within the ${spaceId} space${overwrite ? ' with overwrite enabled' : ''}`;
+        const { unauthorized, authorized, superuser } = createTests(overwrite!, spaceId);
+        const _addTests = (user: TestUser, tests: CreateTestDefinition[]) => {
+          addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+        };
 
-      createTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-        },
-      });
-    });
+        [
+          users.noAccess,
+          users.legacyAll,
+          users.dualRead,
+          users.readGlobally,
+          users.readAtSpace,
+          users.allAtOtherSpace,
+        ].forEach(user => {
+          _addTests(user, unauthorized);
+        });
+        [users.dualAll, users.allGlobally, users.allAtSpace].forEach(user => {
+          _addTests(user, authorized);
+        });
+        _addTests(users.superuser, superuser);
+      }
+    );
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts
index bfd2112428db4..995b8fc2422d9 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts
@@ -4,288 +4,83 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { deleteTestSuiteFactory } from '../../common/suites/delete';
+import {
+  deleteTestSuiteFactory,
+  TEST_CASES as CASES,
+  DeleteTestDefinition,
+} from '../../common/suites/delete';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('delete', () => {
-    const {
-      createExpectUnknownDocNotFound,
-      deleteTest,
-      expectEmpty,
-      expectRbacSpaceAwareForbidden,
-      expectRbacNotSpaceAwareForbidden,
-      expectRbacInvalidIdForbidden,
-      expectGenericNotFound,
-      expectRbacHiddenTypeForbidden,
-    } = deleteTestSuiteFactory(esArchiver, supertest);
-
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      deleteTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectRbacSpaceAwareForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectRbacNotSpaceAwareForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 403,
-            response: expectRbacInvalidIdForbidden,
-          },
-        },
-      });
-
-      deleteTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          hiddenType: {
-            statusCode: 404,
-            response: expectGenericNotFound,
-          },
-          invalidId: {
-            statusCode: 404,
-            response: createExpectUnknownDocNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      deleteTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectRbacSpaceAwareForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectRbacNotSpaceAwareForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 403,
-            response: expectRbacInvalidIdForbidden,
-          },
-        },
-      });
-
-      deleteTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 404,
-            response: createExpectUnknownDocNotFound(scenario.spaceId),
-          },
-        },
-      });
+  const { addTests, createTestDefinitions } = deleteTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(spaceId);
+    return {
+      unauthorized: createTestDefinitions(allTypes, true, { spaceId }),
+      authorized: [
+        createTestDefinitions(normalTypes, false, { spaceId }),
+        createTestDefinitions(hiddenType, true, { spaceId }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, { spaceId }),
+    };
+  };
 
-      deleteTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectRbacSpaceAwareForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectRbacNotSpaceAwareForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 403,
-            response: expectRbacInvalidIdForbidden,
-          },
-        },
-      });
+  describe('_delete', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized, superuser } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: DeleteTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      deleteTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 404,
-            response: createExpectUnknownDocNotFound(scenario.spaceId),
-          },
-        },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.readAtSpace,
+        users.allAtOtherSpace,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      deleteTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectRbacSpaceAwareForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectRbacNotSpaceAwareForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 403,
-            response: expectRbacInvalidIdForbidden,
-          },
-        },
-      });
-
-      deleteTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectEmpty,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 404,
-            response: createExpectUnknownDocNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      deleteTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectRbacSpaceAwareForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectRbacNotSpaceAwareForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 403,
-            response: expectRbacInvalidIdForbidden,
-          },
-        },
-      });
-
-      deleteTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectRbacSpaceAwareForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectRbacNotSpaceAwareForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacHiddenTypeForbidden,
-          },
-          invalidId: {
-            statusCode: 403,
-            response: expectRbacInvalidIdForbidden,
-          },
-        },
+      [users.dualAll, users.allGlobally, users.allAtSpace].forEach(user => {
+        _addTests(user, authorized);
       });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/export.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/export.ts
index b64c3ed87c35d..6f2426e55c6a6 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/export.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/export.ts
@@ -4,274 +4,70 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
-import { SPACES } from '../../common/lib/spaces';
+import { getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { exportTestSuiteFactory } from '../../common/suites/export';
+import {
+  exportTestSuiteFactory,
+  getTestCases,
+  ExportTestDefinition,
+} from '../../common/suites/export';
+
+const createTestCases = (spaceId: string) => {
+  const cases = getTestCases(spaceId);
+  const exportableTypes = [
+    cases.singleNamespaceObject,
+    cases.singleNamespaceType,
+    cases.namespaceAgnosticObject,
+    cases.namespaceAgnosticType,
+  ];
+  const nonExportableTypes = [
+    cases.multiNamespaceObject,
+    cases.multiNamespaceType,
+    cases.hiddenObject,
+    cases.hiddenType,
+  ];
+  const allTypes = exportableTypes.concat(nonExportableTypes);
+  return { exportableTypes, nonExportableTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('export', () => {
-    const {
-      createExpectRbacForbidden,
-      expectTypeOrObjectsRequired,
-      createExpectVisualizationResults,
-      expectInvalidTypeSpecified,
-      exportTest,
-    } = exportTestSuiteFactory(esArchiver, supertest);
+  const { addTests, createTestDefinitions } = exportTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const { exportableTypes, nonExportableTypes, allTypes } = createTestCases(spaceId);
+    return {
+      unauthorized: [
+        createTestDefinitions(exportableTypes, true),
+        createTestDefinitions(nonExportableTypes, false),
+      ].flat(),
+      authorized: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      exportTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
+  describe('_export', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: ExportTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      exportTest(`superuser with the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
+      [users.noAccess, users.legacyAll, users.allAtOtherSpace].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      exportTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
-      });
-
-      exportTest(`rbac user with all at the other space within ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          hiddenType: {
-            description: 'exporting space not allowed',
-            statusCode: 400,
-            response: expectInvalidTypeSpecified,
-          },
-          noTypeOrObjects: {
-            description: 'bad request, type or object is required',
-            statusCode: 400,
-            response: expectTypeOrObjectsRequired,
-          },
-        },
+      [
+        users.dualAll,
+        users.dualRead,
+        users.allGlobally,
+        users.readGlobally,
+        users.allAtSpace,
+        users.readAtSpace,
+        users.superuser,
+      ].forEach(user => {
+        _addTests(user, authorized);
       });
     });
   });
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/find.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/find.ts
index 366b8b44585cd..7c16c01d203c0 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/find.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/find.ts
@@ -4,727 +4,71 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
-import { SPACES } from '../../common/lib/spaces';
+import { getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { findTestSuiteFactory } from '../../common/suites/find';
+import { findTestSuiteFactory, getTestCases, FindTestDefinition } from '../../common/suites/find';
+
+const createTestCases = (spaceId: string) => {
+  const cases = getTestCases(spaceId);
+  const normalTypes = [
+    cases.singleNamespaceType,
+    cases.multiNamespaceType,
+    cases.namespaceAgnosticType,
+    cases.pageBeyondTotal,
+    cases.unknownSearchField,
+    cases.filterWithNamespaceAgnosticType,
+    cases.filterWithDisallowedType,
+  ];
+  const hiddenAndUnknownTypes = [
+    cases.hiddenType,
+    cases.unknownType,
+    cases.filterWithHiddenType,
+    cases.filterWithUnknownType,
+  ];
+  const allTypes = normalTypes.concat(hiddenAndUnknownTypes);
+  return { normalTypes, hiddenAndUnknownTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('find', () => {
-    const {
-      createExpectEmpty,
-      createExpectRbacForbidden,
-      createExpectVisualizationResults,
-      expectFilterWrongTypeError,
-      expectNotSpaceAwareResults,
-      expectTypeRequired,
-      findTest,
-    } = findTestSuiteFactory(esArchiver, supertest);
+  const { addTests, createTestDefinitions } = findTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const { normalTypes, hiddenAndUnknownTypes, allTypes } = createTestCases(spaceId);
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenAndUnknownTypes, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      findTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          notSpaceAwareType: {
-            description: 'forbidden login and find globaltype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          unknownSearchField: {
-            description: 'forbidden login and find url message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('url'),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'forbidden login and find globaltype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'forbidden',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-        },
-      });
+  describe('_find', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized, superuser } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: FindTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      findTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          unknownType: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          filterWithUnknownType: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
+      [users.noAccess, users.legacyAll, users.allAtOtherSpace].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      findTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          notSpaceAwareType: {
-            description: 'forbidden login and find globaltype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          unknownSearchField: {
-            description: 'forbidden login and find url message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('url'),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'forbidden login and find globaltype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'forbidden',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-        },
-      });
-
-      findTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
-      });
-
-      findTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
-      });
-
-      findTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
-      });
-
-      findTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
-      });
-
-      findTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
-      });
-
-      findTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'only the visualization',
-            statusCode: 200,
-            response: createExpectVisualizationResults(scenario.spaceId),
-          },
-          notSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(100, 100, 1),
-          },
-          unknownSearchField: {
-            description: 'empty result',
-            statusCode: 200,
-            response: createExpectEmpty(1, 20, 0),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'only the globaltype',
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'Bad Request',
-            statusCode: 400,
-            response: expectFilterWrongTypeError,
-          },
-        },
-      });
-
-      findTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAwareType: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          notSpaceAwareType: {
-            description: 'forbidden login and find globaltype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-          hiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          unknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          pageBeyondTotal: {
-            description: 'forbidden login and find visualization message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('visualization'),
-          },
-          unknownSearchField: {
-            description: 'forbidden login and find url message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('url'),
-          },
-          noType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithNotSpaceAwareType: {
-            description: 'forbidden login and find globaltype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-          filterWithHiddenType: {
-            description: 'forbidden find hiddentype message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('hiddentype'),
-          },
-          filterWithUnknownType: {
-            description: 'forbidden find wigwags message',
-            statusCode: 403,
-            response: createExpectRbacForbidden('wigwags'),
-          },
-          filterWithNoType: {
-            description: 'bad request, type is required',
-            statusCode: 400,
-            response: expectTypeRequired,
-          },
-          filterWithUnAllowedType: {
-            description: 'forbidden',
-            statusCode: 403,
-            response: createExpectRbacForbidden('globaltype'),
-          },
-        },
+      [
+        users.dualAll,
+        users.dualRead,
+        users.allGlobally,
+        users.readGlobally,
+        users.allAtSpace,
+        users.readAtSpace,
+      ].forEach(user => {
+        _addTests(user, authorized);
       });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts
index 9667abcc5e57a..9e3203e147493 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts
@@ -4,289 +4,84 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { getTestSuiteFactory } from '../../common/suites/get';
+import {
+  getTestSuiteFactory,
+  TEST_CASES as CASES,
+  GetTestDefinition,
+} from '../../common/suites/get';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  const {
-    createExpectDoesntExistNotFound,
-    createExpectSpaceAwareResults,
-    createExpectNotSpaceAwareResults,
-    expectSpaceAwareRbacForbidden,
-    expectNotSpaceAwareRbacForbidden,
-    expectDoesntExistRbacForbidden,
-    expectHiddenTypeRbacForbidden,
-    expectHiddenTypeNotFound,
-    getTest,
-  } = getTestSuiteFactory(esArchiver, supertest);
-
-  describe('get', () => {
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      getTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      getTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 404,
-            response: expectHiddenTypeNotFound,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      getTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      getTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
+  const { addTests, createTestDefinitions } = getTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(spaceId);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenType, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-      getTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
+  describe('_get', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized, superuser } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: GetTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      getTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
+      [users.noAccess, users.legacyAll, users.allAtOtherSpace].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      getTest(`rbac user with read globall within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      getTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      getTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: createExpectSpaceAwareResults(scenario.spaceId),
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: createExpectNotSpaceAwareResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      getTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
+      [
+        users.dualAll,
+        users.dualRead,
+        users.allGlobally,
+        users.readGlobally,
+        users.allAtSpace,
+        users.readAtSpace,
+      ].forEach(user => {
+        _addTests(user, authorized);
       });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts
index 58859c292ce35..10c7f61dce5cc 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts
@@ -4,245 +4,92 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { importTestSuiteFactory } from '../../common/suites/import';
+import {
+  importTestSuiteFactory,
+  TEST_CASES as CASES,
+  ImportTestDefinition,
+} from '../../common/suites/import';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const importableTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(spaceId === DEFAULT_SPACE_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(spaceId === SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(spaceId === SPACE_2_ID) },
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409() },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const nonImportableTypes = [
+    { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail400() },
+    { ...CASES.HIDDEN, ...fail400() },
+    { ...CASES.NEW_MULTI_NAMESPACE_OBJ, ...fail400() },
+  ];
+  const allTypes = importableTypes.concat(nonImportableTypes);
+  return { importableTypes, nonImportableTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    importTest,
-    createExpectResults,
-    expectRbacForbidden,
-    expectUnknownTypeUnsupported: expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
-  } = importTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = importTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = (spaceId: string) => {
+    const { importableTypes, nonImportableTypes, allTypes } = createTestCases(spaceId);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: [
+        createTestDefinitions(importableTypes, true, { spaceId }),
+        createTestDefinitions(nonImportableTypes, false, { spaceId, singleRequest: true }),
+        createTestDefinitions(allTypes, true, {
+          spaceId,
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['dashboard', 'globaltype', 'isolatedtype']),
+        }),
+      ].flat(),
+      authorized: createTestDefinitions(allTypes, false, { spaceId, singleRequest: true }),
+    };
+  };
 
   describe('_import', () => {
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      importTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      importTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
-
-      importTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      importTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: ImportTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      importTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.readAtSpace,
+        users.allAtOtherSpace,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      importTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
-
-      importTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      importTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
-
-      importTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      importTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
+      [users.dualAll, users.allGlobally, users.allAtSpace, users.superuser].forEach(user => {
+        _addTests(user, authorized);
       });
     });
   });
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts
index bb42c5422ece5..46d7ab6425989 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts
@@ -20,6 +20,7 @@ export default function({ getService, loadTestFile }: FtrProviderContext) {
 
     loadTestFile(require.resolve('./bulk_create'));
     loadTestFile(require.resolve('./bulk_get'));
+    loadTestFile(require.resolve('./bulk_update'));
     loadTestFile(require.resolve('./create'));
     loadTestFile(require.resolve('./delete'));
     loadTestFile(require.resolve('./export'));
@@ -28,6 +29,5 @@ export default function({ getService, loadTestFile }: FtrProviderContext) {
     loadTestFile(require.resolve('./import'));
     loadTestFile(require.resolve('./resolve_import_errors'));
     loadTestFile(require.resolve('./update'));
-    loadTestFile(require.resolve('./bulk_update'));
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts
index 6c91fe6310170..8e8fe874b4317 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts
@@ -4,258 +4,99 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { resolveImportErrorsTestSuiteFactory } from '../../common/suites/resolve_import_errors';
+import {
+  resolveImportErrorsTestSuiteFactory,
+  TEST_CASES as CASES,
+  ResolveImportErrorsTestDefinition,
+} from '../../common/suites/resolve_import_errors';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean, spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const importableTypes = [
+    {
+      ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+      ...fail409(!overwrite && spaceId === DEFAULT_SPACE_ID),
+    },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) },
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const nonImportableTypes = [
+    { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail400() },
+    { ...CASES.HIDDEN, ...fail400() },
+    { ...CASES.NEW_MULTI_NAMESPACE_OBJ, ...fail400() },
+  ];
+  const allTypes = importableTypes.concat(nonImportableTypes);
+  return { importableTypes, nonImportableTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    resolveImportErrorsTest,
-    createExpectResults,
-    expectRbacForbidden,
-    expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
-  } = resolveImportErrorsTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = resolveImportErrorsTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = (overwrite: boolean, spaceId: string) => {
+    const { importableTypes, nonImportableTypes, allTypes } = createTestCases(overwrite, spaceId);
+    const singleRequest = true;
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: [
+        createTestDefinitions(importableTypes, true, overwrite, { spaceId }),
+        createTestDefinitions(nonImportableTypes, false, overwrite, { spaceId, singleRequest }),
+        createTestDefinitions(allTypes, true, overwrite, {
+          spaceId,
+          singleRequest,
+          responseBodyOverride: expectForbidden(['dashboard', 'globaltype', 'isolatedtype']),
+        }),
+      ].flat(),
+      authorized: createTestDefinitions(allTypes, false, overwrite, { spaceId, singleRequest }),
+    };
+  };
 
   describe('_resolve_import_errors', () => {
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      resolveImportErrorsTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      resolveImportErrorsTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
-
-      resolveImportErrorsTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      resolveImportErrorsTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
-
-      resolveImportErrorsTest(
-        `dual-privileges readonly user within the ${scenario.spaceId} space`,
-        {
-          user: scenario.users.dualRead,
-          spaceId: scenario.spaceId,
-          tests: {
-            default: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-            hiddenType: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-            unknownType: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-          },
-        }
-      );
-
-      resolveImportErrorsTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 200,
-            response: createExpectResults(scenario.spaceId),
-          },
-          hiddenType: {
-            statusCode: 200,
-            response: expectHiddenTypeUnsupported,
-          },
-          unknownType: {
-            statusCode: 200,
-            response: expectUnknownTypeUnsupported,
-          },
-        },
-      });
-
-      resolveImportErrorsTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          default: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-          unknownType: {
-            statusCode: 403,
-            response: expectRbacForbidden,
-          },
-        },
-      });
-
-      resolveImportErrorsTest(
-        `rbac user with all at the space within the ${scenario.spaceId} space`,
-        {
-          user: scenario.users.allAtSpace,
-          spaceId: scenario.spaceId,
-          tests: {
-            default: {
-              statusCode: 200,
-              response: createExpectResults(scenario.spaceId),
-            },
-            hiddenType: {
-              statusCode: 200,
-              response: expectHiddenTypeUnsupported,
-            },
-            unknownType: {
-              statusCode: 200,
-              response: expectUnknownTypeUnsupported,
-            },
-          },
-        }
-      );
-
-      resolveImportErrorsTest(
-        `rbac user with read at the space within the ${scenario.spaceId} space`,
-        {
-          user: scenario.users.readAtSpace,
-          spaceId: scenario.spaceId,
-          tests: {
-            default: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-            hiddenType: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-            unknownType: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-          },
-        }
-      );
+    getTestScenarios([false, true]).securityAndSpaces.forEach(
+      ({ spaceId, users, modifier: overwrite }) => {
+        const suffix = ` within the ${spaceId} space${overwrite ? ' with overwrite enabled' : ''}`;
+        const { unauthorized, authorized } = createTests(overwrite!, spaceId);
+        const _addTests = (user: TestUser, tests: ResolveImportErrorsTestDefinition[]) => {
+          addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+        };
 
-      resolveImportErrorsTest(
-        `rbac user with all at other space within the ${scenario.spaceId} space`,
-        {
-          user: scenario.users.allAtOtherSpace,
-          spaceId: scenario.spaceId,
-          tests: {
-            default: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-            hiddenType: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-            unknownType: {
-              statusCode: 403,
-              response: expectRbacForbidden,
-            },
-          },
-        }
-      );
-    });
+        [
+          users.noAccess,
+          users.legacyAll,
+          users.dualRead,
+          users.readGlobally,
+          users.readAtSpace,
+          users.allAtOtherSpace,
+        ].forEach(user => {
+          _addTests(user, unauthorized);
+        });
+        [users.dualAll, users.allGlobally, users.allAtSpace, users.superuser].forEach(user => {
+          _addTests(user, authorized);
+        });
+      }
+    );
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts
index 8eb06e41e2a41..21f354d2a8e76 100644
--- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts
+++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts
@@ -4,289 +4,83 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { updateTestSuiteFactory } from '../../common/suites/update';
+import {
+  updateTestSuiteFactory,
+  TEST_CASES as CASES,
+  UpdateTestDefinition,
+} from '../../common/suites/update';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    {
+      ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+      ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+    },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('update', () => {
-    const {
-      createExpectDoesntExistNotFound,
-      expectDoesntExistRbacForbidden,
-      expectNotSpaceAwareResults,
-      expectNotSpaceAwareRbacForbidden,
-      expectSpaceAwareRbacForbidden,
-      expectSpaceAwareResults,
-      expectSpaceNotFound,
-      expectHiddenTypeRbacForbidden,
-      updateTest,
-    } = updateTestSuiteFactory(esArchiver, supertest);
-
-    [
-      {
-        spaceId: SPACES.DEFAULT.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-        },
-      },
-      {
-        spaceId: SPACES.SPACE_1.spaceId,
-        users: {
-          noAccess: AUTHENTICATION.NOT_A_KIBANA_USER,
-          superuser: AUTHENTICATION.SUPERUSER,
-          legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER,
-          allGlobally: AUTHENTICATION.KIBANA_RBAC_USER,
-          readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-          dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-          dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-          allAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-          readAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-          allAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-        },
-      },
-    ].forEach(scenario => {
-      updateTest(`user with no access within the ${scenario.spaceId} space`, {
-        user: scenario.users.noAccess,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      updateTest(`superuser within the ${scenario.spaceId} space`, {
-        user: scenario.users.superuser,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 404,
-            response: expectSpaceNotFound,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      updateTest(`legacy user within the ${scenario.spaceId} space`, {
-        user: scenario.users.legacyAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      updateTest(`dual-privileges user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualAll,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
+  const { addTests, createTestDefinitions } = updateTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(spaceId);
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenType, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-      updateTest(`dual-privileges readonly user within the ${scenario.spaceId} space`, {
-        user: scenario.users.dualRead,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
+  describe('_update', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` within the ${spaceId} space`;
+      const { unauthorized, authorized, superuser } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: UpdateTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
 
-      updateTest(`rbac user with all globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.allGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.readAtSpace,
+        users.allAtOtherSpace,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
       });
-
-      updateTest(`rbac user with read globally within the ${scenario.spaceId} space`, {
-        user: scenario.users.readGlobally,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      updateTest(`rbac user with all at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 200,
-            response: expectSpaceAwareResults,
-          },
-          notSpaceAware: {
-            statusCode: 200,
-            response: expectNotSpaceAwareResults,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 404,
-            response: createExpectDoesntExistNotFound(scenario.spaceId),
-          },
-        },
-      });
-
-      updateTest(`rbac user with read at the space within the ${scenario.spaceId} space`, {
-        user: scenario.users.readAtSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
-      });
-
-      updateTest(`rbac user with all at other space within the ${scenario.spaceId} space`, {
-        user: scenario.users.allAtOtherSpace,
-        spaceId: scenario.spaceId,
-        tests: {
-          spaceAware: {
-            statusCode: 403,
-            response: expectSpaceAwareRbacForbidden,
-          },
-          notSpaceAware: {
-            statusCode: 403,
-            response: expectNotSpaceAwareRbacForbidden,
-          },
-          hiddenType: {
-            statusCode: 403,
-            response: expectHiddenTypeRbacForbidden,
-          },
-          doesntExist: {
-            statusCode: 403,
-            response: expectDoesntExistRbacForbidden,
-          },
-        },
+      [users.dualAll, users.allGlobally, users.allAtSpace].forEach(user => {
+        _addTests(user, authorized);
       });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts
index 943a22c4399c7..5b3397c7909ae 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts
@@ -4,176 +4,88 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkCreateTestSuiteFactory } from '../../common/suites/bulk_create';
+import {
+  bulkCreateTestSuiteFactory,
+  TEST_CASES as CASES,
+  BulkCreateTestDefinition,
+} from '../../common/suites/bulk_create';
+
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(!overwrite) },
+    CASES.SINGLE_NAMESPACE_SPACE_1,
+    CASES.SINGLE_NAMESPACE_SPACE_2,
+    { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409() },
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_MULTI_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail400() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    bulkCreateTest,
-    createExpectResults,
-    createExpectRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectedForbiddenTypesWithHiddenType: expectedForbiddenTypesWithHiddenType,
-  } = bulkCreateTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = bulkCreateTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = (overwrite: boolean) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(overwrite);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true, overwrite),
+      authorized: [
+        createTestDefinitions(normalTypes, false, overwrite, { singleRequest: true }),
+        createTestDefinitions(hiddenType, true, overwrite),
+        createTestDefinitions(allTypes, true, overwrite, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['hiddentype']),
+        }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, overwrite, { singleRequest: true }),
+    };
+  };
 
   describe('_bulk_create', () => {
-    bulkCreateTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkCreateTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingSpace: {
-          statusCode: 200,
-          response: expectBadRequestForHiddenType,
-        },
-      },
-    });
-
-    bulkCreateTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkCreateTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(['hiddentype']),
-        },
-      },
-    });
-
-    bulkCreateTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkCreateTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(['hiddentype']),
-        },
-      },
-    });
-
-    bulkCreateTest(`rbac readonly user`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkCreateTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkCreateTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkCreateTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
+    getTestScenarios([false, true]).security.forEach(({ users, modifier: overwrite }) => {
+      const suffix = overwrite ? ' with overwrite enabled' : '';
+      const { unauthorized, authorized, superuser } = createTests(overwrite!);
+      const _addTests = (user: TestUser, tests: BulkCreateTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, tests });
+      };
 
-    bulkCreateTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingSpace: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts
index fde98694fe575..69494ed254669 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts
@@ -4,175 +4,81 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkGetTestSuiteFactory } from '../../common/suites/bulk_get';
+import {
+  bulkGetTestSuiteFactory,
+  TEST_CASES as CASES,
+  BulkGetTestDefinition,
+} from '../../common/suites/bulk_get';
+
+const { fail400, fail404 } = testCaseFailures;
+
+const createTestCases = () => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() },
+    CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail400() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  const {
-    bulkGetTest,
-    createExpectResults,
-    createExpectRbacForbidden,
-    expectedForbiddenTypesWithHiddenType,
-    expectBadRequestForHiddenType,
-  } = bulkGetTestSuiteFactory(esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = bulkGetTestSuiteFactory(
+    esArchiver,
+    supertest
+  );
+  const createTests = () => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases();
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false, { singleRequest: true }),
+        createTestDefinitions(hiddenType, true),
+        createTestDefinitions(allTypes, true, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['hiddentype']),
+        }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, { singleRequest: true }),
+    };
+  };
 
   describe('_bulk_get', () => {
-    bulkGetTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkGetTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingHiddenType: {
-          statusCode: 200,
-          response: expectBadRequestForHiddenType,
-        },
-      },
-    });
-
-    bulkGetTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkGetTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(['hiddentype']),
-        },
-      },
-    });
-
-    bulkGetTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(['hiddentype']),
-        },
-      },
-    });
-
-    bulkGetTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(['hiddentype']),
-        },
-      },
-    });
-
-    bulkGetTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(['hiddentype']),
-        },
-      },
-    });
-
-    bulkGetTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkGetTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
-
-    bulkGetTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
-    });
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized, superuser } = createTests();
+      const _addTests = (user: TestUser, tests: BulkGetTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    bulkGetTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(),
-        },
-        includingHiddenType: {
-          statusCode: 403,
-          response: createExpectRbacForbidden(expectedForbiddenTypesWithHiddenType),
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.dualRead, users.allGlobally, users.readGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts
index 6f4635f17cf8c..fb169f4c6fb86 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts
@@ -4,268 +4,83 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkUpdateTestSuiteFactory } from '../../common/suites/bulk_update';
+import {
+  bulkUpdateTestSuiteFactory,
+  TEST_CASES as CASES,
+  BulkUpdateTestDefinition,
+} from '../../common/suites/bulk_update';
+
+const { fail404 } = testCaseFailures;
+
+const createTestCases = () => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() },
+    CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('bulkUpdate', () => {
-    const {
-      createExpectDoesntExistNotFound,
-      expectDoesntExistRbacForbidden,
-      expectNotSpaceAwareResults,
-      expectNotSpaceAwareRbacForbidden,
-      expectSpaceAwareRbacForbidden,
-      expectSpaceAwareResults,
-      expectSpaceNotFound,
-      expectHiddenTypeRbacForbidden,
-      expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-      bulkUpdateTest,
-    } = bulkUpdateTestSuiteFactory(esArchiver, supertest);
-
-    bulkUpdateTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    bulkUpdateTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 200,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions, expectForbidden } = bulkUpdateTestSuiteFactory(
+    esArchiver,
+    supertest
+  );
+  const createTests = () => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases();
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false, { singleRequest: true }),
+        createTestDefinitions(hiddenType, true),
+        createTestDefinitions(allTypes, true, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['hiddentype']),
+        }),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, { singleRequest: true }),
+    };
+  };
 
-    bulkUpdateTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    bulkUpdateTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-        },
-        doesntExist: {
-          statusCode: 200,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    bulkUpdateTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    bulkUpdateTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbiddenWithGlobalAllowed,
-        },
-        doesntExist: {
-          statusCode: 200,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    bulkUpdateTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    bulkUpdateTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    bulkUpdateTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    bulkUpdateTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
+  describe('_bulk_update', () => {
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized, superuser } = createTests();
+      const _addTests = (user: TestUser, tests: BulkUpdateTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    bulkUpdateTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/create.ts b/x-pack/test/saved_object_api_integration/security_only/apis/create.ts
index 60a9fa0a86aa6..dc8e564e42477 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/create.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/create.ts
@@ -4,222 +4,79 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { createTestSuiteFactory } from '../../common/suites/create';
+import {
+  createTestSuiteFactory,
+  TEST_CASES as CASES,
+  CreateTestDefinition,
+} from '../../common/suites/create';
 
-export default function({ getService }: FtrProviderContext) {
-  const supertestWithoutAuth = getService('supertestWithoutAuth');
-  const es = getService('legacyEs');
-  const esArchiver = getService('esArchiver');
-
-  const {
-    createTest,
-    createExpectSpaceAwareResults,
-    expectNotSpaceAwareResults,
-    expectNotSpaceAwareRbacForbidden,
-    expectSpaceAwareRbacForbidden,
-    expectBadRequestForHiddenType,
-    expectHiddenTypeRbacForbidden,
-  } = createTestSuiteFactory(es, esArchiver, supertestWithoutAuth);
-
-  describe('create', () => {
-    createTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
+const { fail400, fail409 } = testCaseFailures;
 
-    createTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 400,
-          response: expectBadRequestForHiddenType,
-        },
-      },
-    });
-
-    createTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
+const createTestCases = (overwrite: boolean) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(!overwrite) },
+    CASES.SINGLE_NAMESPACE_SPACE_1,
+    CASES.SINGLE_NAMESPACE_SPACE_2,
+    { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite) },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409() },
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_MULTI_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail400() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
-    createTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
-
-    createTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
-
-    createTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
-
-    createTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
-
-    createTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
+export default function({ getService }: FtrProviderContext) {
+  const supertest = getService('supertestWithoutAuth');
+  const esArchiver = getService('esArchiver');
+  const es = getService('legacyEs');
 
-    createTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = createTestSuiteFactory(es, esArchiver, supertest);
+  const createTests = (overwrite: boolean) => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases(overwrite);
+    return {
+      unauthorized: createTestDefinitions(allTypes, true, overwrite),
+      authorized: [
+        createTestDefinitions(normalTypes, false, overwrite),
+        createTestDefinitions(hiddenType, true, overwrite),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false, overwrite),
+    };
+  };
 
-    createTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
-    });
+  describe('_create', () => {
+    getTestScenarios([false, true]).security.forEach(({ users, modifier: overwrite }) => {
+      const suffix = overwrite ? ' with overwrite enabled' : '';
+      const { unauthorized, authorized, superuser } = createTests(overwrite!);
+      const _addTests = (user: TestUser, tests: CreateTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, tests });
+      };
 
-    createTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts b/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts
index f775b5a365d6b..05939197be352 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts
@@ -4,266 +4,75 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { deleteTestSuiteFactory } from '../../common/suites/delete';
+import {
+  deleteTestSuiteFactory,
+  TEST_CASES as CASES,
+  DeleteTestDefinition,
+} from '../../common/suites/delete';
+
+const { fail404 } = testCaseFailures;
+
+const createTestCases = () => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() },
+    CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('delete', () => {
-    const {
-      createExpectUnknownDocNotFound,
-      deleteTest,
-      expectEmpty,
-      expectRbacSpaceAwareForbidden,
-      expectRbacNotSpaceAwareForbidden,
-      expectRbacInvalidIdForbidden,
-      expectRbacHiddenTypeForbidden: expectRbacSpaceTypeForbidden,
-      expectGenericNotFound,
-    } = deleteTestSuiteFactory(esArchiver, supertest);
-
-    deleteTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
-
-    deleteTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectGenericNotFound,
-        },
-        invalidId: {
-          statusCode: 404,
-          response: createExpectUnknownDocNotFound(),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = deleteTestSuiteFactory(esArchiver, supertest);
+  const createTests = () => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases();
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenType, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    deleteTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
-
-    deleteTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 404,
-          response: createExpectUnknownDocNotFound(),
-        },
-      },
-    });
-
-    deleteTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
-
-    deleteTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 404,
-          response: createExpectUnknownDocNotFound(),
-        },
-      },
-    });
-
-    deleteTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
-
-    deleteTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
-
-    deleteTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
-
-    deleteTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
-    });
+  describe('_delete', () => {
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized, superuser } = createTests();
+      const _addTests = (user: TestUser, tests: DeleteTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    deleteTest(`rbac user with readonly at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectRbacSpaceAwareForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectRbacNotSpaceAwareForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacSpaceTypeForbidden,
-        },
-        invalidId: {
-          statusCode: 403,
-          response: expectRbacInvalidIdForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/export.ts b/x-pack/test/saved_object_api_integration/security_only/apis/export.ts
index 2a2c3a9b90b08..0fae45a1897a7 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/export.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/export.ts
@@ -4,252 +4,75 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { exportTestSuiteFactory } from '../../common/suites/export';
+import {
+  exportTestSuiteFactory,
+  getTestCases,
+  ExportTestDefinition,
+} from '../../common/suites/export';
+
+const createTestCases = () => {
+  const cases = getTestCases();
+  const exportableTypes = [
+    cases.singleNamespaceObject,
+    cases.singleNamespaceType,
+    cases.namespaceAgnosticObject,
+    cases.namespaceAgnosticType,
+  ];
+  const nonExportableTypes = [
+    cases.multiNamespaceObject,
+    cases.multiNamespaceType,
+    cases.hiddenObject,
+    cases.hiddenType,
+  ];
+  const allTypes = exportableTypes.concat(nonExportableTypes);
+  return { exportableTypes, nonExportableTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('export', () => {
-    const {
-      createExpectRbacForbidden,
-      expectTypeOrObjectsRequired,
-      createExpectVisualizationResults,
-      expectInvalidTypeSpecified,
-      exportTest,
-    } = exportTestSuiteFactory(esArchiver, supertest);
-
-    exportTest('user with no access', {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'forbidden login and find visualization message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('superuser', {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('legacy user', {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'forbidden login and find visualization message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('dual-privileges user', {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('dual-privileges readonly user', {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('rbac user with all globally', {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('rbac user with read globally', {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = exportTestSuiteFactory(esArchiver, supertest);
+  const createTests = () => {
+    const { exportableTypes, nonExportableTypes, allTypes } = createTestCases();
+    return {
+      unauthorized: [
+        createTestDefinitions(exportableTypes, true),
+        createTestDefinitions(nonExportableTypes, false),
+      ].flat(),
+      authorized: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    exportTest('rbac user with all at default space', {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('rbac user with read at default space', {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
-
-    exportTest('rbac user with all at space_1', {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
+  describe('_export', () => {
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized } = createTests();
+      const _addTests = (user: TestUser, tests: ExportTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    exportTest('rbac user with read at space_1', {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [
+        users.dualAll,
+        users.dualRead,
+        users.allGlobally,
+        users.readGlobally,
+        users.superuser,
+      ].forEach(user => {
+        _addTests(user, authorized);
+      });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/find.ts b/x-pack/test/saved_object_api_integration/security_only/apis/find.ts
index 64d85a199e7bc..97513783b94b9 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/find.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/find.ts
@@ -4,749 +4,70 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { findTestSuiteFactory } from '../../common/suites/find';
+import { findTestSuiteFactory, getTestCases, FindTestDefinition } from '../../common/suites/find';
+
+const createTestCases = () => {
+  const cases = getTestCases();
+  const normalTypes = [
+    cases.singleNamespaceType,
+    cases.multiNamespaceType,
+    cases.namespaceAgnosticType,
+    cases.pageBeyondTotal,
+    cases.unknownSearchField,
+    cases.filterWithNamespaceAgnosticType,
+    cases.filterWithDisallowedType,
+  ];
+  const hiddenAndUnknownTypes = [
+    cases.hiddenType,
+    cases.unknownType,
+    cases.filterWithHiddenType,
+    cases.filterWithUnknownType,
+  ];
+  const allTypes = normalTypes.concat(hiddenAndUnknownTypes);
+  return { normalTypes, hiddenAndUnknownTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('find', () => {
-    const {
-      createExpectEmpty,
-      createExpectRbacForbidden,
-      createExpectVisualizationResults,
-      expectFilterWrongTypeError,
-      expectNotSpaceAwareResults,
-      expectTypeRequired,
-      findTest,
-    } = findTestSuiteFactory(esArchiver, supertest);
-
-    findTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'forbidden login and find visualization message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        notSpaceAwareType: {
-          description: 'forbidden login and find globaltype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        hiddenType: {
-          description: 'forbidden login and find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'forbidden login and find visualization message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        unknownSearchField: {
-          description: 'forbidden login and unknown search field',
-          statusCode: 403,
-          response: createExpectRbacForbidden('url'),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'forbidden login and find globaltype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        filterWithHiddenType: {
-          description: 'forbidden login and find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'forbidden',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-      },
-    });
-
-    findTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        unknownType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        filterWithUnknownType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
-    });
-
-    findTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'forbidden login and find visualization message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        notSpaceAwareType: {
-          description: 'forbidden login and find globaltype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        hiddenType: {
-          description: 'forbidden login and find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'forbidden login and find visualization message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        unknownSearchField: {
-          description: 'forbidden login and unknown search field',
-          statusCode: 403,
-          response: createExpectRbacForbidden('url'),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'forbidden login and find globaltype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        filterWithHiddenType: {
-          description: 'forbidden login and find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'forbidden',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-      },
-    });
-
-    findTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
-    });
-
-    findTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
-    });
-
-    findTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
-    });
-
-    findTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = findTestSuiteFactory(esArchiver, supertest);
+  const createTests = () => {
+    const { normalTypes, hiddenAndUnknownTypes, allTypes } = createTestCases();
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenAndUnknownTypes, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    findTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        unknownSearchField: {
-          description: 'forbidden login and unknown search field',
-          statusCode: 403,
-          response: createExpectRbacForbidden('url'),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'forbidden',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-      },
-    });
-
-    findTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        unknownSearchField: {
-          description: 'forbidden login and unknown search field',
-          statusCode: 403,
-          response: createExpectRbacForbidden('url'),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'forbidden',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-      },
-    });
-
-    findTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        unknownSearchField: {
-          description: 'forbidden login and unknown search field',
-          statusCode: 403,
-          response: createExpectRbacForbidden('url'),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'forbidden',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-      },
-    });
+  describe('_find', () => {
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized, superuser } = createTests();
+      const _addTests = (user: TestUser, tests: FindTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    findTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        notSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        hiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        unknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 403,
-          response: createExpectRbacForbidden('visualization'),
-        },
-        unknownSearchField: {
-          description: 'forbidden login and unknown search field',
-          statusCode: 403,
-          response: createExpectRbacForbidden('url'),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the globaltype',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-        filterWithHiddenType: {
-          description: 'forbidden find hiddentype message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('hiddentype'),
-        },
-        filterWithUnknownType: {
-          description: 'forbidden find wigwags message',
-          statusCode: 403,
-          response: createExpectRbacForbidden('wigwags'),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'forbidden',
-          statusCode: 403,
-          response: createExpectRbacForbidden('globaltype'),
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.dualRead, users.allGlobally, users.readGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/get.ts b/x-pack/test/saved_object_api_integration/security_only/apis/get.ts
index 2a31463fce8b2..7cd50fe4cea61 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/get.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/get.ts
@@ -4,267 +4,73 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { getTestSuiteFactory } from '../../common/suites/get';
+import {
+  getTestSuiteFactory,
+  TEST_CASES as CASES,
+  GetTestDefinition,
+} from '../../common/suites/get';
+
+const { fail404 } = testCaseFailures;
+
+const createTestCases = () => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() },
+    CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  const {
-    createExpectDoesntExistNotFound,
-    createExpectSpaceAwareResults,
-    createExpectNotSpaceAwareResults,
-    expectSpaceAwareRbacForbidden,
-    expectNotSpaceAwareRbacForbidden,
-    expectDoesntExistRbacForbidden,
-    expectHiddenTypeRbacForbidden,
-    expectHiddenTypeNotFound,
-    getTest,
-  } = getTestSuiteFactory(esArchiver, supertest);
-
-  describe('get', () => {
-    getTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    getTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(),
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectHiddenTypeNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = getTestSuiteFactory(esArchiver, supertest);
+  const createTests = () => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases();
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenType, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    getTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    getTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(),
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    getTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(),
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    getTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(),
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    getTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(),
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    getTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    getTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    getTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
+  describe('_get', () => {
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized, superuser } = createTests();
+      const _addTests = (user: TestUser, tests: GetTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    getTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.dualRead, users.allGlobally, users.readGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/import.ts b/x-pack/test/saved_object_api_integration/security_only/apis/import.ts
index 770410dcfed81..5a6e530b02939 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/import.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/import.ts
@@ -4,223 +4,87 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { importTestSuiteFactory } from '../../common/suites/import';
+import {
+  importTestSuiteFactory,
+  TEST_CASES as CASES,
+  ImportTestDefinition,
+} from '../../common/suites/import';
+
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = () => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const importableTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409() },
+    CASES.SINGLE_NAMESPACE_SPACE_1,
+    CASES.SINGLE_NAMESPACE_SPACE_2,
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409() },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const nonImportableTypes = [
+    { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail400() },
+    { ...CASES.HIDDEN, ...fail400() },
+    { ...CASES.NEW_MULTI_NAMESPACE_OBJ, ...fail400() },
+  ];
+  const allTypes = importableTypes.concat(nonImportableTypes);
+  return { importableTypes, nonImportableTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    importTest,
-    createExpectResults,
-    expectRbacForbidden,
-    expectUnknownTypeUnsupported,
-    expectResultsWithUnsupportedHiddenType,
-  } = importTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = importTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = () => {
+    const { importableTypes, nonImportableTypes, allTypes } = createTestCases();
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: [
+        createTestDefinitions(importableTypes, true),
+        createTestDefinitions(nonImportableTypes, false, { singleRequest: true }),
+        createTestDefinitions(allTypes, true, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['dashboard', 'globaltype', 'isolatedtype']),
+        }),
+      ].flat(),
+      authorized: createTestDefinitions(allTypes, false, { singleRequest: true }),
+    };
+  };
 
   describe('_import', () => {
-    importTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    importTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        hiddenType: {
-          // import filters out the space type, so the remaining objects will import successfully
-          statusCode: 200,
-          response: expectResultsWithUnsupportedHiddenType,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    importTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    importTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        hiddenType: {
-          // import filters out the space type, so the remaining objects will import successfully
-          statusCode: 200,
-          response: expectResultsWithUnsupportedHiddenType,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    importTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    importTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        hiddenType: {
-          // import filters out the space type, so the remaining objects will import successfully
-          statusCode: 200,
-          response: expectResultsWithUnsupportedHiddenType,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    importTest(`rbac readonly user`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    importTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    importTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    importTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized } = createTests();
+      const _addTests = (user: TestUser, tests: ImportTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    importTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally, users.superuser].forEach(user => {
+        _addTests(user, authorized);
+      });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/index.ts b/x-pack/test/saved_object_api_integration/security_only/apis/index.ts
index bb637a9bc4c90..f581e18ff17af 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/index.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/index.ts
@@ -20,6 +20,7 @@ export default function({ getService, loadTestFile }: FtrProviderContext) {
 
     loadTestFile(require.resolve('./bulk_create'));
     loadTestFile(require.resolve('./bulk_get'));
+    loadTestFile(require.resolve('./bulk_update'));
     loadTestFile(require.resolve('./create'));
     loadTestFile(require.resolve('./delete'));
     loadTestFile(require.resolve('./export'));
@@ -28,6 +29,5 @@ export default function({ getService, loadTestFile }: FtrProviderContext) {
     loadTestFile(require.resolve('./import'));
     loadTestFile(require.resolve('./resolve_import_errors'));
     loadTestFile(require.resolve('./update'));
-    loadTestFile(require.resolve('./bulk_update'));
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts
index 59d50c16c259a..f945d2b64c432 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts
@@ -4,221 +4,88 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { resolveImportErrorsTestSuiteFactory } from '../../common/suites/resolve_import_errors';
+import {
+  resolveImportErrorsTestSuiteFactory,
+  TEST_CASES as CASES,
+  ResolveImportErrorsTestDefinition,
+} from '../../common/suites/resolve_import_errors';
+
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean) => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const importableTypes = [
+    { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(!overwrite) },
+    CASES.SINGLE_NAMESPACE_SPACE_1,
+    CASES.SINGLE_NAMESPACE_SPACE_2,
+    { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+    CASES.NEW_SINGLE_NAMESPACE_OBJ,
+    CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+  ];
+  const nonImportableTypes = [
+    { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail400() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail400() },
+    { ...CASES.HIDDEN, ...fail400() },
+    { ...CASES.NEW_MULTI_NAMESPACE_OBJ, ...fail400() },
+  ];
+  const allTypes = importableTypes.concat(nonImportableTypes);
+  return { importableTypes, nonImportableTypes, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    resolveImportErrorsTest,
-    createExpectResults,
-
-    expectRbacForbidden,
-    expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
-  } = resolveImportErrorsTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions, expectForbidden } = resolveImportErrorsTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = (overwrite: boolean) => {
+    const { importableTypes, nonImportableTypes, allTypes } = createTestCases(overwrite);
+    // use singleRequest to reduce execution time and/or test combined cases
+    return {
+      unauthorized: [
+        createTestDefinitions(importableTypes, true, overwrite),
+        createTestDefinitions(nonImportableTypes, false, overwrite, { singleRequest: true }),
+        createTestDefinitions(allTypes, true, overwrite, {
+          singleRequest: true,
+          responseBodyOverride: expectForbidden(['dashboard', 'globaltype', 'isolatedtype']),
+        }),
+      ].flat(),
+      authorized: createTestDefinitions(allTypes, false, overwrite, { singleRequest: true }),
+    };
+  };
 
   describe('_resolve_import_errors', () => {
-    resolveImportErrorsTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`rbac readonly user`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
-
-    resolveImportErrorsTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
-    });
+    getTestScenarios([false, true]).security.forEach(({ users, modifier: overwrite }) => {
+      const suffix = overwrite ? ' with overwrite enabled' : '';
+      const { unauthorized, authorized } = createTests(overwrite!);
+      const _addTests = (user: TestUser, tests: ResolveImportErrorsTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, tests });
+      };
 
-    resolveImportErrorsTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        default: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-        unknownType: {
-          statusCode: 403,
-          response: expectRbacForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally, users.superuser].forEach(user => {
+        _addTests(user, authorized);
+      });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/update.ts b/x-pack/test/saved_object_api_integration/security_only/apis/update.ts
index 8564296bdf558..e1e3a5f8a7dc7 100644
--- a/x-pack/test/saved_object_api_integration/security_only/apis/update.ts
+++ b/x-pack/test/saved_object_api_integration/security_only/apis/update.ts
@@ -4,267 +4,75 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AUTHENTICATION } from '../../common/lib/authentication';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
+import { TestUser } from '../../common/lib/types';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { updateTestSuiteFactory } from '../../common/suites/update';
+import {
+  updateTestSuiteFactory,
+  TEST_CASES as CASES,
+  UpdateTestDefinition,
+} from '../../common/suites/update';
+
+const { fail404 } = testCaseFailures;
+
+const createTestCases = () => {
+  // for each permitted (non-403) outcome, if failure !== undefined then we expect
+  // to receive an error; otherwise, we expect to receive a success result
+  const normalTypes = [
+    CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() },
+    { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() },
+    CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() },
+    { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() },
+    CASES.NAMESPACE_AGNOSTIC,
+    { ...CASES.DOES_NOT_EXIST, ...fail404() },
+  ];
+  const hiddenType = [{ ...CASES.HIDDEN, ...fail404() }];
+  const allTypes = normalTypes.concat(hiddenType);
+  return { normalTypes, hiddenType, allTypes };
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
 
-  describe('update', () => {
-    const {
-      createExpectDoesntExistNotFound,
-      expectDoesntExistRbacForbidden,
-      expectNotSpaceAwareResults,
-      expectNotSpaceAwareRbacForbidden,
-      expectSpaceAwareRbacForbidden,
-      expectSpaceAwareResults,
-      expectSpaceNotFound,
-      expectHiddenTypeRbacForbidden,
-      updateTest,
-    } = updateTestSuiteFactory(esArchiver, supertest);
-
-    updateTest(`user with no access`, {
-      user: AUTHENTICATION.NOT_A_KIBANA_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    updateTest(`superuser`, {
-      user: AUTHENTICATION.SUPERUSER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = updateTestSuiteFactory(esArchiver, supertest);
+  const createTests = () => {
+    const { normalTypes, hiddenType, allTypes } = createTestCases();
+    return {
+      unauthorized: createTestDefinitions(allTypes, true),
+      authorized: [
+        createTestDefinitions(normalTypes, false),
+        createTestDefinitions(hiddenType, true),
+      ].flat(),
+      superuser: createTestDefinitions(allTypes, false),
+    };
+  };
 
-    updateTest(`legacy user`, {
-      user: AUTHENTICATION.KIBANA_LEGACY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    updateTest(`dual-privileges user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    updateTest(`dual-privileges readonly user`, {
-      user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    updateTest(`rbac user with all globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
-    });
-
-    updateTest(`rbac user with read globally`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    updateTest(`rbac user with all at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    updateTest(`rbac user with read at default space`, {
-      user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
-
-    updateTest(`rbac user with all at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
-    });
+  describe('_update', () => {
+    getTestScenarios().security.forEach(({ users }) => {
+      const { unauthorized, authorized, superuser } = createTests();
+      const _addTests = (user: TestUser, tests: UpdateTestDefinition[]) => {
+        addTests(user.description, { user, tests });
+      };
 
-    updateTest(`rbac user with read at space_1`, {
-      user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
-      tests: {
-        spaceAware: {
-          statusCode: 403,
-          response: expectSpaceAwareRbacForbidden,
-        },
-        notSpaceAware: {
-          statusCode: 403,
-          response: expectNotSpaceAwareRbacForbidden,
-        },
-        hiddenType: {
-          statusCode: 403,
-          response: expectHiddenTypeRbacForbidden,
-        },
-        doesntExist: {
-          statusCode: 403,
-          response: expectDoesntExistRbacForbidden,
-        },
-      },
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.allAtDefaultSpace,
+        users.readAtDefaultSpace,
+        users.allAtSpace1,
+        users.readAtSpace1,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      [users.dualAll, users.allGlobally].forEach(user => {
+        _addTests(user, authorized);
+      });
+      _addTests(users.superuser, superuser);
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts
index 690e358b744d5..70d74822a8b0f 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts
@@ -6,83 +6,72 @@
 
 import expect from '@kbn/expect';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkCreateTestSuiteFactory } from '../../common/suites/bulk_create';
+import { bulkCreateTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/bulk_create';
 
-const expectNamespaceSpecifiedBadRequest = (resp: { [key: string]: any }) => {
-  expect(resp.body).to.eql({
-    error: 'Bad Request',
-    message: '[request body.0.namespace]: definition for this key is missing',
-    statusCode: 400,
-  });
-};
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean, spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  {
+    ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    ...fail409(!overwrite && spaceId === DEFAULT_SPACE_ID),
+  },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409(!overwrite || spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409(!overwrite || spaceId !== SPACE_2_ID) },
+  { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+  { ...CASES.HIDDEN, ...fail400() },
+  CASES.NEW_SINGLE_NAMESPACE_OBJ,
+  CASES.NEW_MULTI_NAMESPACE_OBJ,
+  CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    bulkCreateTest,
-    createExpectResults,
-    expectBadRequestForHiddenType,
-  } = bulkCreateTestSuiteFactory(es, esArchiver, supertest);
-
-  describe('_bulk_create', () => {
-    bulkCreateTest('in the current space (space_1)', {
-      ...SPACES.SPACE_1,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.SPACE_1.spaceId),
-        },
-        includingSpace: {
-          statusCode: 200,
-          response: expectBadRequestForHiddenType,
-        },
-        custom: {
-          description: 'when a namespace is specified on the saved object',
-          requestBody: [
-            {
-              type: 'visualization',
-              namespace: 'space_1',
-              attributes: {
-                title: 'something',
-              },
-            },
-          ],
-          statusCode: 400,
-          response: expectNamespaceSpecifiedBadRequest,
+  const { addTests, createTestDefinitions } = bulkCreateTestSuiteFactory(es, esArchiver, supertest);
+  const createTests = (overwrite: boolean, spaceId: string) => {
+    const testCases = createTestCases(overwrite, spaceId);
+    return createTestDefinitions(testCases, false, overwrite, {
+      spaceId,
+      singleRequest: true,
+    }).concat(
+      ['namespace', 'namespaces'].map(key => ({
+        title: `(bad request) when ${key} is specified on the saved object`,
+        request: [{ type: 'isolatedtype', id: 'some-id', [key]: 'any-value' }] as any,
+        responseStatusCode: 400,
+        responseBody: async (response: Record<string, any>) => {
+          expect(response.body).to.eql({
+            statusCode: 400,
+            error: 'Bad Request',
+            message: `[request body.0.${key}]: definition for this key is missing`,
+          });
         },
-      },
-    });
+        overwrite,
+      }))
+    );
+  };
 
-    bulkCreateTest('in the default space', {
-      ...SPACES.DEFAULT,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.DEFAULT.spaceId),
-        },
-        includingSpace: {
-          statusCode: 200,
-          response: expectBadRequestForHiddenType,
-        },
-        custom: {
-          description: 'when a namespace is specified on the saved object',
-          requestBody: [
-            {
-              type: 'visualization',
-              namespace: 'space_1',
-              attributes: {
-                title: 'something',
-              },
-            },
-          ],
-          statusCode: 400,
-          response: expectNamespaceSpecifiedBadRequest,
-        },
-      },
+  describe('_bulk_create', () => {
+    getTestScenarios([false, true]).spaces.forEach(({ spaceId, modifier: overwrite }) => {
+      const suffix = overwrite ? ' with overwrite enabled' : '';
+      const tests = createTests(overwrite!, spaceId);
+      addTests(`within the ${spaceId} space${suffix}`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts
index bed29f8eb39a1..ad10719750585 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts
@@ -5,48 +5,48 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkGetTestSuiteFactory } from '../../common/suites/bulk_get';
+import { bulkGetTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/bulk_get';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  CASES.NAMESPACE_AGNOSTIC,
+  { ...CASES.HIDDEN, ...fail400() },
+  { ...CASES.DOES_NOT_EXIST, ...fail404() },
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  const {
-    bulkGetTest,
-    createExpectResults,
-    createExpectNotFoundResults,
-    expectBadRequestForHiddenType,
-  } = bulkGetTestSuiteFactory(esArchiver, supertest);
+  const { addTests, createTestDefinitions } = bulkGetTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false, { singleRequest: true });
+  };
 
   describe('_bulk_get', () => {
-    bulkGetTest(`objects within the current space (space_1)`, {
-      ...SPACES.SPACE_1,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.SPACE_1.spaceId),
-        },
-        includingHiddenType: {
-          statusCode: 200,
-          response: expectBadRequestForHiddenType,
-        },
-      },
-    });
-
-    bulkGetTest(`objects within another space`, {
-      ...SPACES.SPACE_1,
-      otherSpaceId: SPACES.SPACE_2.spaceId,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectNotFoundResults(SPACES.SPACE_2.spaceId),
-        },
-        includingHiddenType: {
-          statusCode: 200,
-          response: expectBadRequestForHiddenType,
-        },
-      },
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts
index 0681908a765ce..be6ce9e30c56e 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts
@@ -5,88 +5,48 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { bulkUpdateTestSuiteFactory } from '../../common/suites/bulk_update';
+import { bulkUpdateTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/bulk_update';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  CASES.NAMESPACE_AGNOSTIC,
+  { ...CASES.HIDDEN, ...fail404() },
+  { ...CASES.DOES_NOT_EXIST, ...fail404() },
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  describe('bulkUpdate', () => {
-    const {
-      createExpectSpaceAwareNotFound,
-      expectSpaceAwareResults,
-      createExpectDoesntExistNotFound,
-      expectNotSpaceAwareResults,
-      expectSpaceNotFound,
-      bulkUpdateTest,
-    } = bulkUpdateTestSuiteFactory(esArchiver, supertest);
-
-    bulkUpdateTest(`in the default space`, {
-      spaceId: SPACES.DEFAULT.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 200,
-          response: createExpectDoesntExistNotFound(SPACES.DEFAULT.spaceId),
-        },
-      },
-    });
-
-    bulkUpdateTest('in the current space (space_1)', {
-      spaceId: SPACES.SPACE_1.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 200,
-          response: createExpectDoesntExistNotFound(SPACES.SPACE_1.spaceId),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = bulkUpdateTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false, { singleRequest: true });
+  };
 
-    bulkUpdateTest('objects that exist in another space (space_1)', {
-      spaceId: SPACES.DEFAULT.spaceId,
-      otherSpaceId: SPACES.SPACE_1.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareNotFound(SPACES.SPACE_1.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 200,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
+  describe('_bulk_update', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts
index 3bd4019649363..d0c6a21e73971 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts
@@ -4,90 +4,56 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import expect from '@kbn/expect';
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { createTestSuiteFactory } from '../../common/suites/create';
+import { createTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/create';
 
-const expectNamespaceSpecifiedBadRequest = (resp: { [key: string]: any }) => {
-  expect(resp.body).to.eql({
-    error: 'Bad Request',
-    message: '[request body.namespace]: definition for this key is missing',
-    statusCode: 400,
-  });
-};
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean, spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  {
+    ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    ...fail409(!overwrite && spaceId === DEFAULT_SPACE_ID),
+  },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409(!overwrite || spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409(!overwrite || spaceId !== SPACE_2_ID) },
+  { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+  { ...CASES.HIDDEN, ...fail400() },
+  CASES.NEW_SINGLE_NAMESPACE_OBJ,
+  CASES.NEW_MULTI_NAMESPACE_OBJ,
+  CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+];
 
 export default function({ getService }: FtrProviderContext) {
-  const supertestWithoutAuth = getService('supertestWithoutAuth');
-  const es = getService('legacyEs');
+  const supertest = getService('supertestWithoutAuth');
   const esArchiver = getService('esArchiver');
+  const es = getService('legacyEs');
 
-  const {
-    createTest,
-    createExpectSpaceAwareResults,
-    expectNotSpaceAwareResults,
-    expectBadRequestForHiddenType,
-  } = createTestSuiteFactory(es, esArchiver, supertestWithoutAuth);
-
-  describe('create', () => {
-    createTest('in the current space (space_1)', {
-      ...SPACES.SPACE_1,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(SPACES.SPACE_1.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 400,
-          response: expectBadRequestForHiddenType,
-        },
-        custom: {
-          description: 'when a namespace is specified on the saved object',
-          type: 'visualization',
-          requestBody: {
-            namespace: 'space_1',
-            attributes: {
-              title: 'something',
-            },
-          },
-          statusCode: 400,
-          response: expectNamespaceSpecifiedBadRequest,
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = createTestSuiteFactory(es, esArchiver, supertest);
+  const createTests = (overwrite: boolean, spaceId: string) => {
+    const testCases = createTestCases(overwrite, spaceId);
+    return createTestDefinitions(testCases, false, overwrite, { spaceId });
+  };
 
-    createTest('in the default space', {
-      ...SPACES.DEFAULT,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(SPACES.DEFAULT.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 400,
-          response: expectBadRequestForHiddenType,
-        },
-        custom: {
-          description: 'when a namespace is specified on the saved object',
-          type: 'visualization',
-          requestBody: {
-            namespace: 'space_1',
-            attributes: {
-              title: 'something',
-            },
-          },
-          statusCode: 400,
-          response: expectNamespaceSpecifiedBadRequest,
-        },
-      },
+  describe('_create', () => {
+    getTestScenarios([false, true]).spaces.forEach(({ spaceId, modifier: overwrite }) => {
+      const suffix = overwrite ? ' with overwrite enabled' : '';
+      const tests = createTests(overwrite!, spaceId);
+      addTests(`within the ${spaceId} space${suffix}`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts
index 437b3f95024c6..bb48e06d93a09 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts
@@ -5,87 +5,48 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { deleteTestSuiteFactory } from '../../common/suites/delete';
+import { deleteTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/delete';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  CASES.NAMESPACE_AGNOSTIC,
+  { ...CASES.HIDDEN, ...fail404() },
+  { ...CASES.DOES_NOT_EXIST, ...fail404() },
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  describe('delete', () => {
-    const {
-      createExpectSpaceAwareNotFound,
-      createExpectUnknownDocNotFound,
-      deleteTest,
-      expectEmpty,
-      expectGenericNotFound,
-    } = deleteTestSuiteFactory(esArchiver, supertest);
-
-    deleteTest(`in the default space`, {
-      ...SPACES.DEFAULT,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectGenericNotFound,
-        },
-        invalidId: {
-          statusCode: 404,
-          response: createExpectUnknownDocNotFound(SPACES.DEFAULT.spaceId),
-        },
-      },
-    });
-
-    deleteTest(`in the current space (space_1)`, {
-      ...SPACES.SPACE_1,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectGenericNotFound,
-        },
-        invalidId: {
-          statusCode: 404,
-          response: createExpectUnknownDocNotFound(SPACES.SPACE_1.spaceId),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = deleteTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false, { spaceId });
+  };
 
-    deleteTest(`in another space (space_2)`, {
-      spaceId: SPACES.SPACE_1.spaceId,
-      otherSpaceId: SPACES.SPACE_2.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 404,
-          response: createExpectSpaceAwareNotFound(SPACES.SPACE_2.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectEmpty,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectGenericNotFound,
-        },
-        invalidId: {
-          statusCode: 404,
-          response: createExpectUnknownDocNotFound(SPACES.SPACE_2.spaceId),
-        },
-      },
+  describe('_delete', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/export.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/export.ts
index f4be02c05ac88..25d4fbfae990b 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/export.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/export.ts
@@ -4,62 +4,29 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { SPACES } from '../../common/lib/spaces';
+import { getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { exportTestSuiteFactory } from '../../common/suites/export';
+import { exportTestSuiteFactory, getTestCases } from '../../common/suites/export';
+
+const createTestCases = (spaceId: string) => {
+  const cases = getTestCases(spaceId);
+  return Object.values(cases);
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  const {
-    expectTypeOrObjectsRequired,
-    createExpectVisualizationResults,
-    expectInvalidTypeSpecified,
-    exportTest,
-  } = exportTestSuiteFactory(esArchiver, supertest);
-
-  describe('export', () => {
-    exportTest('objects only within the current space (space_1)', {
-      ...SPACES.SPACE_1,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(SPACES.SPACE_1.spaceId),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = exportTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false);
+  };
 
-    exportTest('objects only within the current space (default)', {
-      ...SPACES.DEFAULT,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(SPACES.DEFAULT.spaceId),
-        },
-        hiddenType: {
-          description: 'exporting space not allowed',
-          statusCode: 400,
-          response: expectInvalidTypeSpecified,
-        },
-        noTypeOrObjects: {
-          description: 'bad request, type or object is required',
-          statusCode: 400,
-          response: expectTypeOrObjectsRequired,
-        },
-      },
+  describe('_export', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/find.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/find.ts
index a07d3edf834e9..a15f7de404db8 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/find.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/find.ts
@@ -4,154 +4,29 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { SPACES } from '../../common/lib/spaces';
+import { getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { findTestSuiteFactory } from '../../common/suites/find';
+import { findTestSuiteFactory, getTestCases } from '../../common/suites/find';
+
+const createTestCases = (spaceId: string) => {
+  const cases = getTestCases(spaceId);
+  return Object.values(cases);
+};
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  const {
-    createExpectEmpty,
-    createExpectVisualizationResults,
-    expectFilterWrongTypeError,
-    expectNotSpaceAwareResults,
-    expectTypeRequired,
-    findTest,
-  } = findTestSuiteFactory(esArchiver, supertest);
-
-  describe('find', () => {
-    findTest(`objects only within the current space (space_1)`, {
-      ...SPACES.SPACE_1,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(SPACES.SPACE_1.spaceId),
-        },
-        notSpaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        unknownType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        filterWithUnknownType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = findTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false);
+  };
 
-    findTest(`objects only within the current space (default)`, {
-      ...SPACES.DEFAULT,
-      tests: {
-        spaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: createExpectVisualizationResults(SPACES.DEFAULT.spaceId),
-        },
-        notSpaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        unknownType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        pageBeyondTotal: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(100, 100, 1),
-        },
-        unknownSearchField: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        noType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithNotSpaceAwareType: {
-          description: 'only the visualization',
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        filterWithHiddenType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        filterWithUnknownType: {
-          description: 'empty result',
-          statusCode: 200,
-          response: createExpectEmpty(1, 20, 0),
-        },
-        filterWithNoType: {
-          description: 'bad request, type is required',
-          statusCode: 400,
-          response: expectTypeRequired,
-        },
-        filterWithUnAllowedType: {
-          description: 'Bad Request',
-          statusCode: 400,
-          response: expectFilterWrongTypeError,
-        },
-      },
+  describe('_find', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts
index 592bedd92b4d7..512ae968dd0dd 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts
@@ -5,88 +5,48 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { getTestSuiteFactory } from '../../common/suites/get';
+import { getTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/get';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  CASES.NAMESPACE_AGNOSTIC,
+  { ...CASES.HIDDEN, ...fail404() },
+  { ...CASES.DOES_NOT_EXIST, ...fail404() },
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  const {
-    createExpectDoesntExistNotFound,
-    createExpectSpaceAwareNotFound,
-    createExpectSpaceAwareResults,
-    createExpectNotSpaceAwareResults,
-    expectHiddenTypeNotFound: expectHiddenTypeNotFound,
-    getTest,
-  } = getTestSuiteFactory(esArchiver, supertest);
-
-  describe('get', () => {
-    getTest(`can access objects belonging to the current space (default)`, {
-      ...SPACES.DEFAULT,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(SPACES.DEFAULT.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(SPACES.DEFAULT.spaceId),
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectHiddenTypeNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(SPACES.DEFAULT.spaceId),
-        },
-      },
-    });
-
-    getTest(`can access objects belonging to the current space (space_1)`, {
-      ...SPACES.SPACE_1,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: createExpectSpaceAwareResults(SPACES.SPACE_1.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(SPACES.SPACE_1.spaceId),
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectHiddenTypeNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(SPACES.SPACE_1.spaceId),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = getTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false, { spaceId });
+  };
 
-    getTest(`can't access space aware objects belonging to another space (space_1)`, {
-      spaceId: SPACES.DEFAULT.spaceId,
-      otherSpaceId: SPACES.SPACE_1.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 404,
-          response: createExpectSpaceAwareNotFound(SPACES.SPACE_1.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: createExpectNotSpaceAwareResults(SPACES.SPACE_1.spaceId),
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectHiddenTypeNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(SPACES.SPACE_1.spaceId),
-        },
-      },
+  describe('_get', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts
index c78a0e1cc2cce..5fe4b08d91b54 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts
@@ -5,56 +5,48 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { importTestSuiteFactory } from '../../common/suites/import';
+import { importTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/import';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(spaceId === DEFAULT_SPACE_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(spaceId === SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(spaceId === SPACE_2_ID) },
+  { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail400() },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail400() },
+  { ...CASES.NAMESPACE_AGNOSTIC, ...fail409() },
+  { ...CASES.HIDDEN, ...fail400() },
+  CASES.NEW_SINGLE_NAMESPACE_OBJ,
+  { ...CASES.NEW_MULTI_NAMESPACE_OBJ, ...fail400() },
+  CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    importTest,
-    createExpectResults,
-    expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
-  } = importTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions } = importTestSuiteFactory(es, esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false, { spaceId, singleRequest: true });
+  };
 
   describe('_import', () => {
-    importTest('in the current space (space_1)', {
-      ...SPACES.SPACE_1,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.SPACE_1.spaceId),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    importTest('in the default space', {
-      ...SPACES.DEFAULT,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.DEFAULT.spaceId),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/index.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/index.ts
index bb481e0c98bc1..c2f8339d38c97 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/index.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/index.ts
@@ -12,6 +12,7 @@ export default function({ loadTestFile }: FtrProviderContext) {
 
     loadTestFile(require.resolve('./bulk_create'));
     loadTestFile(require.resolve('./bulk_get'));
+    loadTestFile(require.resolve('./bulk_update'));
     loadTestFile(require.resolve('./create'));
     loadTestFile(require.resolve('./delete'));
     loadTestFile(require.resolve('./export'));
@@ -20,6 +21,5 @@ export default function({ loadTestFile }: FtrProviderContext) {
     loadTestFile(require.resolve('./import'));
     loadTestFile(require.resolve('./resolve_import_errors'));
     loadTestFile(require.resolve('./update'));
-    loadTestFile(require.resolve('./bulk_update'));
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts
index 22a7ab81e5530..04f9ac8414afd 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts
@@ -5,56 +5,59 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { resolveImportErrorsTestSuiteFactory } from '../../common/suites/resolve_import_errors';
+import {
+  resolveImportErrorsTestSuiteFactory,
+  TEST_CASES as CASES,
+} from '../../common/suites/resolve_import_errors';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail400, fail409 } = testCaseFailures;
+
+const createTestCases = (overwrite: boolean, spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  {
+    ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE,
+    ...fail409(!overwrite && spaceId === DEFAULT_SPACE_ID),
+  },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) },
+  { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail400() },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail400() },
+  { ...CASES.NAMESPACE_AGNOSTIC, ...fail409(!overwrite) },
+  { ...CASES.HIDDEN, ...fail400() },
+  CASES.NEW_SINGLE_NAMESPACE_OBJ,
+  { ...CASES.NEW_MULTI_NAMESPACE_OBJ, ...fail400() },
+  CASES.NEW_NAMESPACE_AGNOSTIC_OBJ,
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
   const es = getService('legacyEs');
 
-  const {
-    resolveImportErrorsTest,
-    createExpectResults,
-    expectUnknownTypeUnsupported,
-    expectHiddenTypeUnsupported,
-  } = resolveImportErrorsTestSuiteFactory(es, esArchiver, supertest);
+  const { addTests, createTestDefinitions } = resolveImportErrorsTestSuiteFactory(
+    es,
+    esArchiver,
+    supertest
+  );
+  const createTests = (overwrite: boolean, spaceId: string) => {
+    const testCases = createTestCases(overwrite, spaceId);
+    return createTestDefinitions(testCases, false, overwrite, { spaceId, singleRequest: true });
+  };
 
   describe('_resolve_import_errors', () => {
-    resolveImportErrorsTest('in the current space (space_1)', {
-      ...SPACES.SPACE_1,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.SPACE_1.spaceId),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
-    });
-
-    resolveImportErrorsTest('in the default space', {
-      ...SPACES.DEFAULT,
-      tests: {
-        default: {
-          statusCode: 200,
-          response: createExpectResults(SPACES.DEFAULT.spaceId),
-        },
-        hiddenType: {
-          statusCode: 200,
-          response: expectHiddenTypeUnsupported,
-        },
-        unknownType: {
-          statusCode: 200,
-          response: expectUnknownTypeUnsupported,
-        },
-      },
+    getTestScenarios([false, true]).spaces.forEach(({ spaceId, modifier: overwrite }) => {
+      const suffix = overwrite ? ' with overwrite enabled' : '';
+      const tests = createTests(overwrite!, spaceId);
+      addTests(`within the ${spaceId} space${suffix}`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts
index 6ffbda511d871..381861e33b68d 100644
--- a/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts
+++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts
@@ -5,88 +5,48 @@
  */
 
 import { SPACES } from '../../common/lib/spaces';
+import { testCaseFailures, getTestScenarios } from '../../common/lib/saved_object_test_utils';
 import { FtrProviderContext } from '../../common/ftr_provider_context';
-import { updateTestSuiteFactory } from '../../common/suites/update';
+import { updateTestSuiteFactory, TEST_CASES as CASES } from '../../common/suites/update';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => [
+  // for each outcome, if failure !== undefined then we expect to receive
+  // an error; otherwise, we expect to receive a success result
+  { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  {
+    ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1,
+    ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID),
+  },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) },
+  { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) },
+  CASES.NAMESPACE_AGNOSTIC,
+  { ...CASES.HIDDEN, ...fail404() },
+  { ...CASES.DOES_NOT_EXIST, ...fail404() },
+];
 
 export default function({ getService }: FtrProviderContext) {
   const supertest = getService('supertest');
   const esArchiver = getService('esArchiver');
 
-  describe('update', () => {
-    const {
-      createExpectSpaceAwareNotFound,
-      expectSpaceAwareResults,
-      createExpectDoesntExistNotFound,
-      expectNotSpaceAwareResults,
-      expectSpaceNotFound,
-      updateTest,
-    } = updateTestSuiteFactory(esArchiver, supertest);
-
-    updateTest(`in the default space`, {
-      spaceId: SPACES.DEFAULT.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(SPACES.DEFAULT.spaceId),
-        },
-      },
-    });
-
-    updateTest('in the current space (space_1)', {
-      spaceId: SPACES.SPACE_1.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 200,
-          response: expectSpaceAwareResults,
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(SPACES.SPACE_1.spaceId),
-        },
-      },
-    });
+  const { addTests, createTestDefinitions } = updateTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    return createTestDefinitions(testCases, false);
+  };
 
-    updateTest('objects that exist in another space (space_1)', {
-      spaceId: SPACES.DEFAULT.spaceId,
-      otherSpaceId: SPACES.SPACE_1.spaceId,
-      tests: {
-        spaceAware: {
-          statusCode: 404,
-          response: createExpectSpaceAwareNotFound(SPACES.SPACE_1.spaceId),
-        },
-        notSpaceAware: {
-          statusCode: 200,
-          response: expectNotSpaceAwareResults,
-        },
-        hiddenType: {
-          statusCode: 404,
-          response: expectSpaceNotFound,
-        },
-        doesntExist: {
-          statusCode: 404,
-          response: createExpectDoesntExistNotFound(),
-        },
-      },
+  describe('_update', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createTests(spaceId);
+      addTests(`within the ${spaceId} space`, { spaceId, tests });
     });
   });
 }
diff --git a/x-pack/test/spaces_api_integration/common/config.ts b/x-pack/test/spaces_api_integration/common/config.ts
index dffc6c524cc6e..19743e09f9420 100644
--- a/x-pack/test/spaces_api_integration/common/config.ts
+++ b/x-pack/test/spaces_api_integration/common/config.ts
@@ -67,6 +67,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
           // disable anonymouse access so that we're testing both on and off in different suites
           '--status.allowAnonymous=false',
           '--server.xsrf.disableProtection=true',
+          `--plugin-path=${path.join(__dirname, 'fixtures', 'shared_type_plugin')}`,
           ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`),
         ],
       },
diff --git a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
index 64c1be0b90071..9a8a0a1fdda14 100644
--- a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
+++ b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
@@ -376,3 +376,123 @@
     "type": "_doc"
   }
 }
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:default_space_only",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the default space"
+      },
+      "type": "sharedtype",
+      "namespaces": ["default"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:space_1_only",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the space_1 space"
+      },
+      "type": "sharedtype",
+      "namespaces": ["space_1"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:space_2_only",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the space_2 space"
+      },
+      "type": "sharedtype",
+      "namespaces": ["space_2"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:default_and_space_1",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the default and space_1 spaces"
+      },
+      "type": "sharedtype",
+      "namespaces": ["default", "space_1"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:default_and_space_2",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the default and space_2 spaces"
+      },
+      "type": "sharedtype",
+      "namespaces": ["default", "space_2"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:space_1_and_space_2",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the space_1 and space_2 spaces"
+      },
+      "type": "sharedtype",
+      "namespaces": ["space_1", "space_2"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
+{
+  "type": "doc",
+  "value": {
+    "id": "sharedtype:all_spaces",
+    "index": ".kibana",
+    "source": {
+      "sharedtype": {
+        "title": "A shared saved-object in the default, space_1, and space_2 spaces"
+      },
+      "type": "sharedtype",
+      "namespaces": ["default", "space_1", "space_2"],
+      "updated_at": "2017-09-21T18:59:16.270Z"
+    },
+    "type": "doc"
+  }
+}
+
diff --git a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json
index 1440585b625b9..508de68c32f70 100644
--- a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json
+++ b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json
@@ -159,6 +159,9 @@
         "namespace": {
           "type": "keyword"
         },
+        "namespaces": {
+          "type": "keyword"
+        },
         "search": {
           "properties": {
             "columns": {
@@ -320,6 +323,19 @@
               "type": "text"
             }
           }
+        },
+        "sharedtype": {
+          "properties": {
+            "title": {
+              "type": "text",
+              "fields": {
+                "keyword": {
+                  "type": "keyword",
+                  "ignore_above": 2048
+                }
+              }
+            }
+          }
         }
       }
     },
diff --git a/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/index.js b/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/index.js
new file mode 100644
index 0000000000000..91a24fb9f4f56
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/index.js
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import mappings from './mappings.json';
+
+export default function(kibana) {
+  return new kibana.Plugin({
+    require: ['kibana', 'elasticsearch', 'xpack_main'],
+    name: 'shared_type_plugin',
+    uiExports: {
+      savedObjectsManagement: {},
+      savedObjectSchemas: {
+        sharedtype: {
+          multiNamespace: true,
+        },
+      },
+      mappings,
+    },
+
+    config() {},
+
+    init() {}, // need empty init for plugin to load
+  });
+}
diff --git a/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/mappings.json b/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/mappings.json
new file mode 100644
index 0000000000000..918958aec0d6d
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/mappings.json
@@ -0,0 +1,15 @@
+{
+  "sharedtype": {
+    "properties": {
+      "title": {
+        "type": "text",
+        "fields": {
+          "keyword": {
+            "type": "keyword",
+            "ignore_above": 2048
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/package.json b/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/package.json
new file mode 100644
index 0000000000000..c52f4256c5c06
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/common/fixtures/shared_type_plugin/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "shared_type_plugin",
+  "version": "0.0.0",
+  "kibana": {
+    "version": "kibana"
+  }
+}
diff --git a/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts b/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts
new file mode 100644
index 0000000000000..67f5d737ba010
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES = Object.freeze({
+  DEFAULT_SPACE_ONLY: Object.freeze({
+    id: 'default_space_only',
+    existingNamespaces: ['default'],
+  }),
+  SPACE_1_ONLY: Object.freeze({
+    id: 'space_1_only',
+    existingNamespaces: ['space_1'],
+  }),
+  SPACE_2_ONLY: Object.freeze({
+    id: 'space_2_only',
+    existingNamespaces: ['space_2'],
+  }),
+  DEFAULT_AND_SPACE_1: Object.freeze({
+    id: 'default_and_space_1',
+    existingNamespaces: ['default', 'space_1'],
+  }),
+  DEFAULT_AND_SPACE_2: Object.freeze({
+    id: 'default_and_space_2',
+    existingNamespaces: ['default', 'space_2'],
+  }),
+  SPACE_1_AND_SPACE_2: Object.freeze({
+    id: 'space_1_and_space_2',
+    existingNamespaces: ['space_1', 'space_2'],
+  }),
+  ALL_SPACES: Object.freeze({
+    id: 'all_spaces',
+    existingNamespaces: ['default', 'space_1', 'space_2'],
+  }),
+  DOES_NOT_EXIST: Object.freeze({
+    id: 'does_not_exist',
+    existingNamespaces: [] as string[],
+  }),
+});
diff --git a/x-pack/test/spaces_api_integration/common/suites/delete.ts b/x-pack/test/spaces_api_integration/common/suites/delete.ts
index 9036fcbf7a8dd..0d8728fdf622e 100644
--- a/x-pack/test/spaces_api_integration/common/suites/delete.ts
+++ b/x-pack/test/spaces_api_integration/common/suites/delete.ts
@@ -6,6 +6,7 @@
 import expect from '@kbn/expect';
 import { SuperTest } from 'supertest';
 import { getUrlPrefix } from '../lib/space_test_utils';
+import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
 import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
 
 interface DeleteTest {
@@ -128,6 +129,25 @@ export function deleteTestSuiteFactory(es: any, esArchiver: any, supertest: Supe
     ];
 
     expect(buckets).to.eql(expectedBuckets);
+
+    // There were seven multi-namespace objects.
+    // Since Space 2 was deleted, any multi-namespace objects that existed in that space
+    // are updated to remove it, and of those, any that don't exist in any space are deleted.
+    const multiNamespaceResponse = await es.search({
+      index: '.kibana',
+      body: { query: { terms: { type: ['sharedtype'] } } },
+    });
+    const docs: [Record<string, any>] = multiNamespaceResponse.hits.hits;
+    expect(docs).length(6); // just six results, since spaces_2_only got deleted
+    Object.values(CASES).forEach(({ id, existingNamespaces }) => {
+      const remainingNamespaces = existingNamespaces.filter(x => x !== 'space_2');
+      const doc = docs.find(x => x._id === `sharedtype:${id}`);
+      if (remainingNamespaces.length > 0) {
+        expect(doc?._source?.namespaces).to.eql(remainingNamespaces);
+      } else {
+        expect(doc).to.be(undefined);
+      }
+    });
   };
 
   const expectNotFound = (resp: { [key: string]: any }) => {
diff --git a/x-pack/test/spaces_api_integration/common/suites/share_add.ts b/x-pack/test/spaces_api_integration/common/suites/share_add.ts
new file mode 100644
index 0000000000000..b9a012b606da3
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/common/suites/share_add.ts
@@ -0,0 +1,118 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from '@kbn/expect';
+import { SuperTest } from 'supertest';
+import { SavedObjectsErrorHelpers } from '../../../../../src/core/server';
+import { SPACES } from '../lib/spaces';
+import {
+  expectResponses,
+  getUrlPrefix,
+} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
+import {
+  ExpectResponseBody,
+  TestDefinition,
+  TestSuite,
+} from '../../../saved_object_api_integration/common/lib/types';
+
+export interface ShareAddTestDefinition extends TestDefinition {
+  request: { spaces: string[]; object: { type: string; id: string } };
+}
+export type ShareAddTestSuite = TestSuite<ShareAddTestDefinition>;
+export interface ShareAddTestCase {
+  id: string;
+  namespaces: string[];
+  failure?: 400 | 403 | 404;
+  fail400Param?: string;
+  fail403Param?: string;
+}
+
+const TYPE = 'sharedtype';
+const createRequest = ({ id, namespaces }: ShareAddTestCase) => ({
+  spaces: namespaces,
+  object: { type: TYPE, id },
+});
+const getTestTitle = ({ id, namespaces }: ShareAddTestCase) =>
+  `{id: ${id}, namespaces: [${namespaces.join(',')}]}`;
+
+export function shareAddTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
+  const expectResponseBody = (testCase: ShareAddTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    const { id, failure, fail400Param, fail403Param } = testCase;
+    const object = response.body;
+    if (failure === 403) {
+      await expectResponses.forbidden(fail403Param!)(TYPE)(response);
+    } else if (failure) {
+      let error: any;
+      if (failure === 400) {
+        error = SavedObjectsErrorHelpers.createBadRequestError(
+          `${id} already exists in the following namespace(s): ${fail400Param}`
+        );
+      } else if (failure === 404) {
+        error = SavedObjectsErrorHelpers.createGenericNotFoundError(TYPE, id);
+      }
+      expect(object.error).to.eql(error.output.payload.error);
+      expect(object.statusCode).to.eql(error.output.payload.statusCode);
+    } else {
+      // success
+      expect(object).to.eql({});
+    }
+  };
+  const createTestDefinitions = (
+    testCases: ShareAddTestCase | ShareAddTestCase[],
+    forbidden: boolean,
+    options?: {
+      responseBodyOverride?: ExpectResponseBody;
+      fail403Param?: string;
+    }
+  ): ShareAddTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403, fail403Param: options?.fail403Param }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle(x),
+      responseStatusCode: x.failure ?? 204,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
+  };
+
+  const makeShareAddTest = (describeFn: Mocha.SuiteFunction) => (
+    description: string,
+    definition: ShareAddTestSuite
+  ) => {
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
+
+    describeFn(description, () => {
+      before(() => esArchiver.load('saved_objects/spaces'));
+      after(() => esArchiver.unload('saved_objects/spaces'));
+
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const requestBody = test.request;
+          await supertest
+            .post(`${getUrlPrefix(spaceId)}/api/spaces/_share_saved_object_add`)
+            .auth(user?.username, user?.password)
+            .send(requestBody)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
+        });
+      }
+    });
+  };
+
+  const addTests = makeShareAddTest(describe);
+  // @ts-ignore
+  addTests.only = makeShareAddTest(describe.only);
+
+  return {
+    addTests,
+    createTestDefinitions,
+  };
+}
diff --git a/x-pack/test/spaces_api_integration/common/suites/share_remove.ts b/x-pack/test/spaces_api_integration/common/suites/share_remove.ts
new file mode 100644
index 0000000000000..b5fcbe5a1cf2c
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/common/suites/share_remove.ts
@@ -0,0 +1,116 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from '@kbn/expect';
+import { SuperTest } from 'supertest';
+import { SavedObjectsErrorHelpers } from '../../../../../src/core/server';
+import { SPACES } from '../lib/spaces';
+import {
+  expectResponses,
+  getUrlPrefix,
+  getTestTitle,
+} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
+import {
+  ExpectResponseBody,
+  TestDefinition,
+  TestSuite,
+} from '../../../saved_object_api_integration/common/lib/types';
+
+export interface ShareRemoveTestDefinition extends TestDefinition {
+  request: { spaces: string[]; object: { type: string; id: string } };
+}
+export type ShareRemoveTestSuite = TestSuite<ShareRemoveTestDefinition>;
+export interface ShareRemoveTestCase {
+  id: string;
+  namespaces: string[];
+  failure?: 400 | 403 | 404;
+  fail400Param?: string;
+}
+
+const TYPE = 'sharedtype';
+const createRequest = ({ id, namespaces }: ShareRemoveTestCase) => ({
+  spaces: namespaces,
+  object: { type: TYPE, id },
+});
+
+export function shareRemoveTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
+  const expectForbidden = expectResponses.forbidden('delete');
+  const expectResponseBody = (testCase: ShareRemoveTestCase): ExpectResponseBody => async (
+    response: Record<string, any>
+  ) => {
+    const { id, failure, fail400Param } = testCase;
+    const object = response.body;
+    if (failure === 403) {
+      await expectForbidden(TYPE)(response);
+    } else if (failure) {
+      let error: any;
+      if (failure === 400) {
+        error = SavedObjectsErrorHelpers.createBadRequestError(
+          `${id} doesn't exist in the following namespace(s): ${fail400Param}`
+        );
+      } else if (failure === 404) {
+        error = SavedObjectsErrorHelpers.createGenericNotFoundError(TYPE, id);
+      }
+      expect(object.error).to.eql(error.output.payload.error);
+      expect(object.statusCode).to.eql(error.output.payload.statusCode);
+    } else {
+      // success
+      expect(object).to.eql({});
+    }
+  };
+  const createTestDefinitions = (
+    testCases: ShareRemoveTestCase | ShareRemoveTestCase[],
+    forbidden: boolean,
+    options?: {
+      responseBodyOverride?: ExpectResponseBody;
+    }
+  ): ShareRemoveTestDefinition[] => {
+    let cases = Array.isArray(testCases) ? testCases : [testCases];
+    if (forbidden) {
+      // override the expected result in each test case
+      cases = cases.map(x => ({ ...x, failure: 403 }));
+    }
+    return cases.map(x => ({
+      title: getTestTitle({ ...x, type: TYPE }),
+      responseStatusCode: x.failure ?? 204,
+      request: createRequest(x),
+      responseBody: options?.responseBodyOverride || expectResponseBody(x),
+    }));
+  };
+
+  const makeShareRemoveTest = (describeFn: Mocha.SuiteFunction) => (
+    description: string,
+    definition: ShareRemoveTestSuite
+  ) => {
+    const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;
+
+    describeFn(description, () => {
+      before(() => esArchiver.load('saved_objects/spaces'));
+      after(() => esArchiver.unload('saved_objects/spaces'));
+
+      for (const test of tests) {
+        it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
+          const requestBody = test.request;
+          await supertest
+            .post(`${getUrlPrefix(spaceId)}/api/spaces/_share_saved_object_remove`)
+            .auth(user?.username, user?.password)
+            .send(requestBody)
+            .expect(test.responseStatusCode)
+            .then(test.responseBody);
+        });
+      }
+    });
+  };
+
+  const addTests = makeShareRemoveTest(describe);
+  // @ts-ignore
+  addTests.only = makeShareRemoveTest(describe.only);
+
+  return {
+    addTests,
+    createTestDefinitions,
+  };
+}
diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts
index e918ab0b53841..8d85d95e6812f 100644
--- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts
+++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts
@@ -25,6 +25,8 @@ export default function({ loadTestFile, getService }: TestInvoker) {
     loadTestFile(require.resolve('./delete'));
     loadTestFile(require.resolve('./get_all'));
     loadTestFile(require.resolve('./get'));
+    loadTestFile(require.resolve('./share_add'));
+    loadTestFile(require.resolve('./share_remove'));
     loadTestFile(require.resolve('./update'));
   });
 }
diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts
new file mode 100644
index 0000000000000..c7e65ac424776
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts
@@ -0,0 +1,124 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { SPACES } from '../../common/lib/spaces';
+import {
+  testCaseFailures,
+  getTestScenarios,
+} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
+import { TestUser } from '../../../saved_object_api_integration/common/lib/types';
+import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../../common/lib/saved_object_test_cases';
+import { TestInvoker } from '../../common/lib/types';
+import { shareAddTestSuiteFactory, ShareAddTestDefinition } from '../../common/suites/share_add';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  const namespaces = [spaceId];
+  return [
+    // Test cases to check adding the target namespace to different saved objects
+    { ...CASES.DEFAULT_SPACE_ONLY, namespaces, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SPACE_1_ONLY, namespaces, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SPACE_2_ONLY, namespaces, ...fail404(spaceId !== SPACE_2_ID) },
+    { ...CASES.DEFAULT_AND_SPACE_1, namespaces, ...fail404(spaceId === SPACE_2_ID) },
+    { ...CASES.DEFAULT_AND_SPACE_2, namespaces, ...fail404(spaceId === SPACE_1_ID) },
+    { ...CASES.SPACE_1_AND_SPACE_2, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) },
+    { ...CASES.ALL_SPACES, namespaces },
+    { ...CASES.DOES_NOT_EXIST, namespaces, ...fail404() },
+    // Test cases to check adding multiple namespaces to different saved objects that exist in one space
+    // These are non-exhaustive, they only check cases for adding two additional namespaces to a saved object
+    // More permutations are covered in the corresponding spaces_only test suite
+    {
+      ...CASES.DEFAULT_SPACE_ONLY,
+      namespaces: [SPACE_1_ID, SPACE_2_ID],
+      ...fail404(spaceId !== DEFAULT_SPACE_ID),
+    },
+    {
+      ...CASES.SPACE_1_ONLY,
+      namespaces: [DEFAULT_SPACE_ID, SPACE_2_ID],
+      ...fail404(spaceId !== SPACE_1_ID),
+    },
+    {
+      ...CASES.SPACE_2_ONLY,
+      namespaces: [DEFAULT_SPACE_ID, SPACE_1_ID],
+      ...fail404(spaceId !== SPACE_2_ID),
+    },
+  ];
+};
+const calculateSingleSpaceAuthZ = (
+  testCases: ReturnType<typeof createTestCases>,
+  spaceId: string
+) => {
+  const targetsOtherSpace = testCases.filter(
+    x => !x.namespaces.includes(spaceId) || x.namespaces.length > 1
+  );
+  const tmp = testCases.filter(x => !targetsOtherSpace.includes(x)); // doesn't target other space
+  const doesntExistInThisSpace = tmp.filter(x => !x.existingNamespaces.includes(spaceId));
+  const existsInThisSpace = tmp.filter(x => x.existingNamespaces.includes(spaceId));
+  return { targetsOtherSpace, doesntExistInThisSpace, existsInThisSpace };
+};
+// eslint-disable-next-line import/no-default-export
+export default function({ getService }: TestInvoker) {
+  const supertest = getService('supertestWithoutAuth');
+  const esArchiver = getService('esArchiver');
+
+  const { addTests, createTestDefinitions } = shareAddTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const testCases = createTestCases(spaceId);
+    const thisSpace = calculateSingleSpaceAuthZ(testCases, spaceId);
+    const otherSpaceId = spaceId === DEFAULT_SPACE_ID ? SPACE_1_ID : DEFAULT_SPACE_ID;
+    const otherSpace = calculateSingleSpaceAuthZ(testCases, otherSpaceId);
+    return {
+      unauthorized: createTestDefinitions(testCases, true, { fail403Param: 'create' }),
+      authorizedInSpace: [
+        createTestDefinitions(thisSpace.targetsOtherSpace, true, { fail403Param: 'create' }),
+        createTestDefinitions(thisSpace.doesntExistInThisSpace, false),
+        createTestDefinitions(thisSpace.existsInThisSpace, false),
+      ].flat(),
+      authorizedInOtherSpace: [
+        createTestDefinitions(otherSpace.targetsOtherSpace, true, { fail403Param: 'create' }),
+        // If the preflight GET request fails, it will return a 404 error; users who are authorized to create saved objects in the target
+        // space(s) but are not authorized to update saved objects in this space will see a 403 error instead of 404. This is a safeguard to
+        // prevent potential information disclosure of the spaces that a given saved object may exist in.
+        createTestDefinitions(otherSpace.doesntExistInThisSpace, true, { fail403Param: 'update' }),
+        createTestDefinitions(otherSpace.existsInThisSpace, false),
+      ].flat(),
+      authorized: createTestDefinitions(testCases, false),
+    };
+  };
+
+  describe('_share_saved_object_add', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` targeting the ${spaceId} space`;
+      const { unauthorized, authorizedInSpace, authorizedInOtherSpace, authorized } = createTests(
+        spaceId
+      );
+      const _addTests = (user: TestUser, tests: ShareAddTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
+
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.readAtSpace,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      _addTests(users.allAtSpace, authorizedInSpace);
+      _addTests(users.allAtOtherSpace, authorizedInOtherSpace);
+      [users.dualAll, users.allGlobally, users.superuser].forEach(user => {
+        _addTests(user, authorized);
+      });
+    });
+  });
+}
diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts
new file mode 100644
index 0000000000000..3a8d42f620a3e
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { SPACES } from '../../common/lib/spaces';
+import {
+  testCaseFailures,
+  getTestScenarios,
+} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
+import { TestUser } from '../../../saved_object_api_integration/common/lib/types';
+import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../../common/lib/saved_object_test_cases';
+import { TestInvoker } from '../../common/lib/types';
+import {
+  shareRemoveTestSuiteFactory,
+  ShareRemoveTestCase,
+  ShareRemoveTestDefinition,
+} from '../../common/suites/share_remove';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+const createTestCases = (spaceId: string) => {
+  // Test cases to check removing the target namespace from different saved objects
+  let namespaces = [spaceId];
+  const singleSpace = [
+    { id: CASES.DEFAULT_SPACE_ONLY.id, namespaces, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { id: CASES.SPACE_1_ONLY.id, namespaces, ...fail404(spaceId !== SPACE_1_ID) },
+    { id: CASES.SPACE_2_ONLY.id, namespaces, ...fail404(spaceId !== SPACE_2_ID) },
+    { id: CASES.DEFAULT_AND_SPACE_1.id, namespaces, ...fail404(spaceId === SPACE_2_ID) },
+    { id: CASES.DEFAULT_AND_SPACE_2.id, namespaces, ...fail404(spaceId === SPACE_1_ID) },
+    { id: CASES.SPACE_1_AND_SPACE_2.id, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) },
+    { id: CASES.ALL_SPACES.id, namespaces },
+    { id: CASES.DOES_NOT_EXIST.id, namespaces, ...fail404() },
+  ] as ShareRemoveTestCase[];
+
+  // Test cases to check removing all three namespaces from different saved objects that exist in two spaces
+  // These are non-exhaustive, they only check some cases -- each object will result in a 404, either because
+  // it never existed in the target namespace, or it was removed in one of the test cases above
+  // More permutations are covered in the corresponding spaces_only test suite
+  namespaces = [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID];
+  const multipleSpaces = [
+    { id: CASES.DEFAULT_AND_SPACE_1.id, namespaces, ...fail404() },
+    { id: CASES.DEFAULT_AND_SPACE_2.id, namespaces, ...fail404() },
+    { id: CASES.SPACE_1_AND_SPACE_2.id, namespaces, ...fail404() },
+  ] as ShareRemoveTestCase[];
+
+  const allCases = singleSpace.concat(multipleSpaces);
+  return { singleSpace, multipleSpaces, allCases };
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function({ getService }: TestInvoker) {
+  const supertest = getService('supertestWithoutAuth');
+  const esArchiver = getService('esArchiver');
+
+  const { addTests, createTestDefinitions } = shareRemoveTestSuiteFactory(esArchiver, supertest);
+  const createTests = (spaceId: string) => {
+    const { singleSpace, multipleSpaces, allCases } = createTestCases(spaceId);
+    return {
+      unauthorized: createTestDefinitions(allCases, true),
+      authorizedThisSpace: [
+        createTestDefinitions(singleSpace, false),
+        createTestDefinitions(multipleSpaces, true),
+      ].flat(),
+      authorizedGlobally: createTestDefinitions(allCases, false),
+    };
+  };
+
+  describe('_share_saved_object_remove', () => {
+    getTestScenarios().securityAndSpaces.forEach(({ spaceId, users }) => {
+      const suffix = ` targeting the ${spaceId} space`;
+      const { unauthorized, authorizedThisSpace, authorizedGlobally } = createTests(spaceId);
+      const _addTests = (user: TestUser, tests: ShareRemoveTestDefinition[]) => {
+        addTests(`${user.description}${suffix}`, { user, spaceId, tests });
+      };
+
+      [
+        users.noAccess,
+        users.legacyAll,
+        users.dualRead,
+        users.readGlobally,
+        users.readAtSpace,
+        users.allAtOtherSpace,
+      ].forEach(user => {
+        _addTests(user, unauthorized);
+      });
+      _addTests(users.allAtSpace, authorizedThisSpace);
+      [users.dualAll, users.allGlobally, users.superuser].forEach(user => {
+        _addTests(user, authorizedGlobally);
+      });
+    });
+  });
+}
diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts
index 1182f6bdabcff..b02dc35b58b56 100644
--- a/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts
+++ b/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts
@@ -17,6 +17,8 @@ export default function spacesOnlyTestSuite({ loadTestFile }: TestInvoker) {
     loadTestFile(require.resolve('./delete'));
     loadTestFile(require.resolve('./get_all'));
     loadTestFile(require.resolve('./get'));
+    loadTestFile(require.resolve('./share_add'));
+    loadTestFile(require.resolve('./share_remove'));
     loadTestFile(require.resolve('./update'));
   });
 }
diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts
new file mode 100644
index 0000000000000..f1e603836fa21
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts
@@ -0,0 +1,84 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { SPACES } from '../../common/lib/spaces';
+import {
+  testCaseFailures,
+  getTestScenarios,
+} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
+import { TestInvoker } from '../../common/lib/types';
+import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../../common/lib/saved_object_test_cases';
+import { shareAddTestSuiteFactory } from '../../common/suites/share_add';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+/**
+ * Single-namespace test cases
+ * @param spaceId the namespace to add to each saved object
+ */
+const createSingleTestCases = (spaceId: string) => {
+  const namespaces = ['some-space-id'];
+  return [
+    { ...CASES.DEFAULT_SPACE_ONLY, namespaces, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SPACE_1_ONLY, namespaces, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SPACE_2_ONLY, namespaces, ...fail404(spaceId !== SPACE_2_ID) },
+    { ...CASES.DEFAULT_AND_SPACE_1, namespaces, ...fail404(spaceId === SPACE_2_ID) },
+    { ...CASES.DEFAULT_AND_SPACE_2, namespaces, ...fail404(spaceId === SPACE_1_ID) },
+    { ...CASES.SPACE_1_AND_SPACE_2, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) },
+    { ...CASES.ALL_SPACES, namespaces },
+    { ...CASES.DOES_NOT_EXIST, namespaces, ...fail404() },
+  ];
+};
+/**
+ * Multi-namespace test cases
+ * These are non-exhaustive, but they check different permutations of saved objects and spaces to add
+ */
+const createMultiTestCases = () => {
+  const allSpaces = [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID];
+  let id = CASES.DEFAULT_SPACE_ONLY.id;
+  const one = [{ id, namespaces: allSpaces }];
+  id = CASES.DEFAULT_AND_SPACE_1.id;
+  const two = [{ id, namespaces: allSpaces }];
+  id = CASES.ALL_SPACES.id;
+  const three = [{ id, namespaces: allSpaces }];
+  return { one, two, three };
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function({ getService }: TestInvoker) {
+  const supertest = getService('supertest');
+  const esArchiver = getService('esArchiver');
+
+  const { addTests, createTestDefinitions } = shareAddTestSuiteFactory(esArchiver, supertest);
+  const createSingleTests = (spaceId: string) => {
+    const testCases = createSingleTestCases(spaceId);
+    return createTestDefinitions(testCases, false);
+  };
+  const createMultiTests = () => {
+    const testCases = createMultiTestCases();
+    return {
+      one: createTestDefinitions(testCases.one, false),
+      two: createTestDefinitions(testCases.two, false),
+      three: createTestDefinitions(testCases.three, false),
+    };
+  };
+
+  describe('_share_saved_object_add', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createSingleTests(spaceId);
+      addTests(`targeting the ${spaceId} space`, { spaceId, tests });
+    });
+    const { one, two, three } = createMultiTests();
+    addTests('for a saved object in the default space', { tests: one });
+    addTests('for a saved object in the default and space_1 spaces', { tests: two });
+    addTests('for a saved object in the default, space_1, and space_2 spaces', { tests: three });
+  });
+}
diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts
new file mode 100644
index 0000000000000..15be72c9f09ac
--- /dev/null
+++ b/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { SPACES } from '../../common/lib/spaces';
+import {
+  testCaseFailures,
+  getTestScenarios,
+} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
+import { TestInvoker } from '../../common/lib/types';
+import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../../common/lib/saved_object_test_cases';
+import { shareRemoveTestSuiteFactory } from '../../common/suites/share_remove';
+
+const {
+  DEFAULT: { spaceId: DEFAULT_SPACE_ID },
+  SPACE_1: { spaceId: SPACE_1_ID },
+  SPACE_2: { spaceId: SPACE_2_ID },
+} = SPACES;
+const { fail404 } = testCaseFailures;
+
+/**
+ * Single-namespace test cases
+ * @param spaceId the namespace to remove from each saved object
+ */
+const createSingleTestCases = (spaceId: string) => {
+  const namespaces = [spaceId];
+  return [
+    { ...CASES.DEFAULT_SPACE_ONLY, namespaces, ...fail404(spaceId !== DEFAULT_SPACE_ID) },
+    { ...CASES.SPACE_1_ONLY, namespaces, ...fail404(spaceId !== SPACE_1_ID) },
+    { ...CASES.SPACE_2_ONLY, namespaces, ...fail404(spaceId !== SPACE_2_ID) },
+    { ...CASES.DEFAULT_AND_SPACE_1, namespaces, ...fail404(spaceId === SPACE_2_ID) },
+    { ...CASES.DEFAULT_AND_SPACE_2, namespaces, ...fail404(spaceId === SPACE_1_ID) },
+    { ...CASES.SPACE_1_AND_SPACE_2, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) },
+    { ...CASES.ALL_SPACES, namespaces },
+    { ...CASES.DOES_NOT_EXIST, namespaces, ...fail404() },
+  ];
+};
+/**
+ * Multi-namespace test cases
+ * These are non-exhaustive, but they check different permutations of saved objects and spaces to remove
+ */
+const createMultiTestCases = () => {
+  const nonExistentSpaceId = 'does_not_exist'; // space that doesn't exist
+  let id = CASES.DEFAULT_SPACE_ONLY.id;
+  const one = [
+    { id, namespaces: [nonExistentSpaceId] },
+    { id, namespaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID] },
+    { id, namespaces: [DEFAULT_SPACE_ID], ...fail404() }, // this saved object no longer exists
+  ];
+  id = CASES.DEFAULT_AND_SPACE_1.id;
+  const two = [
+    { id, namespaces: [DEFAULT_SPACE_ID, nonExistentSpaceId] },
+    // this saved object will not be found in the context of the current namespace ('default')
+    { id, namespaces: [DEFAULT_SPACE_ID], ...fail404() }, // this object's namespaces no longer contains DEFAULT_SPACE_ID
+    { id, namespaces: [SPACE_1_ID], ...fail404() }, // this object's namespaces does contain SPACE_1_ID
+  ];
+  id = CASES.ALL_SPACES.id;
+  const three = [
+    { id, namespaces: [DEFAULT_SPACE_ID, SPACE_1_ID, nonExistentSpaceId] },
+    // this saved object will not be found in the context of the current namespace ('default')
+    { id, namespaces: [DEFAULT_SPACE_ID], ...fail404() }, // this object's namespaces no longer contains DEFAULT_SPACE_ID
+    { id, namespaces: [SPACE_1_ID], ...fail404() }, // this object's namespaces no longer contains SPACE_1_ID
+    { id, namespaces: [SPACE_2_ID], ...fail404() }, // this object's namespaces does contain SPACE_2_ID
+  ];
+  return { one, two, three };
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function({ getService }: TestInvoker) {
+  const supertest = getService('supertest');
+  const esArchiver = getService('esArchiver');
+
+  const { addTests, createTestDefinitions } = shareRemoveTestSuiteFactory(esArchiver, supertest);
+  const createSingleTests = (spaceId: string) => {
+    const testCases = createSingleTestCases(spaceId);
+    return createTestDefinitions(testCases, false);
+  };
+  const createMultiTests = () => {
+    const testCases = createMultiTestCases();
+    return {
+      one: createTestDefinitions(testCases.one, false),
+      two: createTestDefinitions(testCases.two, false),
+      three: createTestDefinitions(testCases.three, false),
+    };
+  };
+
+  describe('_share_saved_object_remove', () => {
+    getTestScenarios().spaces.forEach(({ spaceId }) => {
+      const tests = createSingleTests(spaceId);
+      addTests(`targeting the ${spaceId} space`, { spaceId, tests });
+    });
+    const { one, two, three } = createMultiTests();
+    addTests('for a saved object in the default space', { tests: one });
+    addTests('for a saved object in the default and space_1 spaces', { tests: two });
+    addTests('for a saved object in the default, space_1, and space_2 spaces', { tests: three });
+  });
+}

From 83b9417d4534f7c8d2c6daa9009bd20e1937cf16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cau=C3=AA=20Marcondes?=
 <55978943+cauemarcondes@users.noreply.github.com>
Date: Fri, 10 Apr 2020 08:28:06 +0100
Subject: [PATCH 45/78] [APM] Custom links submit button is off screen in IE11
 (#63122)

---
 .../CustomLinkFlyout/DeleteButton.tsx         |  2 +
 .../CustomLinkFlyout/FlyoutFooter.tsx         | 38 ++++++++-----------
 2 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx
index 2b3a5cbe87992..87cb171518ea4 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx
@@ -8,6 +8,7 @@ import { EuiButtonEmpty } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { NotificationsStart } from 'kibana/public';
 import React, { useState } from 'react';
+import { px, unit } from '../../../../../../style/variables';
 import { callApmApi } from '../../../../../../services/rest/createCallApmApi';
 import { useApmPluginContext } from '../../../../../../hooks/useApmPluginContext';
 
@@ -31,6 +32,7 @@ export function DeleteButton({ onDelete, customLinkId }: Props) {
         setIsDeleting(false);
         onDelete();
       }}
+      style={{ marginRight: px(unit) }}
     >
       {i18n.translate('xpack.apm.settings.customizeUI.customLink.delete', {
         defaultMessage: 'Delete'
diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx
index cb27221309812..96505d639bcdd 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx
@@ -40,29 +40,23 @@ export const FlyoutFooter = ({
             )}
           </EuiButtonEmpty>
         </EuiFlexItem>
-        <EuiFlexItem grow={false}>
-          <EuiFlexGroup>
-            {customLinkId && (
-              <EuiFlexItem>
-                <DeleteButton customLinkId={customLinkId} onDelete={onDelete} />
-              </EuiFlexItem>
+        <EuiFlexItem grow={false} style={{ display: 'block' }}>
+          {customLinkId && (
+            <DeleteButton customLinkId={customLinkId} onDelete={onDelete} />
+          )}
+          <EuiButton
+            fill
+            type="submit"
+            isLoading={isSaving}
+            isDisabled={!isSaveButtonEnabled}
+          >
+            {i18n.translate(
+              'xpack.apm.settings.customizeUI.customLink.flyout.save',
+              {
+                defaultMessage: 'Save'
+              }
             )}
-            <EuiFlexItem>
-              <EuiButton
-                fill
-                type="submit"
-                isLoading={isSaving}
-                isDisabled={!isSaveButtonEnabled}
-              >
-                {i18n.translate(
-                  'xpack.apm.settings.customizeUI.customLink.flyout.save',
-                  {
-                    defaultMessage: 'Save'
-                  }
-                )}
-              </EuiButton>
-            </EuiFlexItem>
-          </EuiFlexGroup>
+          </EuiButton>
         </EuiFlexItem>
       </EuiFlexGroup>
     </EuiFlyoutFooter>

From 34b1d0a10d529da48f35106d6b82cf96498e6677 Mon Sep 17 00:00:00 2001
From: MadameSheema <snootchie.boochies@gmail.com>
Date: Fri, 10 Apr 2020 11:28:59 +0200
Subject: [PATCH 46/78] [SIEM] Updates cypress readme with documentation about
 the test data. (#62747)

* updates test data section

* Update x-pack/legacy/plugins/siem/cypress/README.md

Co-Authored-By: Ryland Herrick <ryalnd@gmail.com>

Co-authored-by: Ryland Herrick <ryalnd@gmail.com>
---
 x-pack/legacy/plugins/siem/cypress/README.md | 132 +++++++++++++++----
 1 file changed, 107 insertions(+), 25 deletions(-)

diff --git a/x-pack/legacy/plugins/siem/cypress/README.md b/x-pack/legacy/plugins/siem/cypress/README.md
index 41137ce6d8a9d..a031fea172be5 100644
--- a/x-pack/legacy/plugins/siem/cypress/README.md
+++ b/x-pack/legacy/plugins/siem/cypress/README.md
@@ -111,6 +111,112 @@ elasticsearch:
   hosts: ['https://<server>:9200']
 ```
 
+## Running (Headless) Tests on the Command Line as a Jenkins execution (The preferred way)
+
+To run (headless) tests as a Jenkins execution.
+
+1. First bootstrap kibana changes from the Kibana root directory:
+
+```sh
+yarn kbn bootstrap
+```
+
+2. Launch Cypress command line test runner:
+
+```sh 
+cd x-pack/legacy/plugins/siem
+yarn cypress:run-as-ci
+```
+
+Note that with this type of execution you don't need to have running a kibana and elasticsearch instance. This is because
+ the command, as it would happen in the CI, will launch the instances. The elasticsearch instance will be fed with the data 
+ placed in: `x-pack/test/siem_cypress/es_archives`
+ 
+As in this case we want to mimic a CI execution we want to execute the tests with the same set of data, this is why 
+in this case does not make sense to override Cypress environment variables. 
+
+### Test data
+
+As said before when running the tests as Jenkins the tests are fed with the data placed in: `x-pack/test/siem_cypress/es_archives`.
+
+Currently there are two different ways of feeding data:
+1. By default
+2. Specifying a specific set of data for a specific test
+
+#### By default
+
+When a execution of the test is going to be done an empty kibana and a set of audibteat data are loaded (empty_kibana and auditbeat). With this data usually is enough to cover most of the scenarios that we are testing.
+
+#### Running tests with custom data
+
+Sometimes the default data is not enough and we need a specific set of data in order to being able to test the desired behaviour.
+
+In that case in the hooks of the test use the function `esArchiverLoad` to load the set of data neeed and `esArchiverUnload` to remove the changes done in the data.
+
+Example:
+
+```typescript
+import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
+
+describe('This are going to be a set of tests', () => {
+  before(() => {
+    esArchiverLoad('name_of_the_data_set_you_want_to_load');
+  });
+
+  after(() => {
+    esArchiverUnload('name_of_the_data_set_you_want_to_unload');
+  });
+
+  it('Going to test something awesome', () => {
+    hereGoesYourAwesomeTestcode     
+  });
+});
+
+```
+
+Note that loading and unloading data takes a signifcant amount of time so try to minimize the use of it when possible.
+
+### Current sets of data
+
+The current sets of data can be found in: `x-pack/test/siem_cypress/es_archives` folder.
+
+- auditbeat
+  - Auditbeat data generated in Sep, 2019 with the following hosts present: 
+    - suricata-iowa
+    - siem-kibana
+    - siem-es
+    - jessie
+- closed_signals
+  - Set of data with 108 closed signals linked to "Signals test" custom rule.
+- custome_rules
+  - Set if data with just 4 custom activated rules. 
+- empty_kibana
+  - Empty kibana board.
+- prebuilt_rules_loaded
+  - Elastic prebuilt loaded rules and deactivated. 
+- signals
+  - Set of data with 108 opened signals linked to "Signals test" custom rule.
+
+### How to generate new test data
+
+We are using es_archiver in order to generate the data that our Cypress tests needs.
+
+1. Setup if possible a clean instance of kibana and elasticsearch (if not, possible please try to clean the data that you are going to generate).
+2. With the kibana and elasticsearch instance up and running, create the data that you need for your test.
+3. When you are sure that you have all the data you need run the following command from: `x-pack/legacy/plugins/siem`
+
+```sh 
+node ../../../../scripts/es_archiver save <nameOfTheFolderWhereDataIsSaved> <indexPatternsToBeSaved>  --dir ../../../test/siem_cypress/es_archives --config ../../../../test/functional/config.js --es-url http://<elasticsearchUsername>:<elasticsearchPassword>@<elasticsearchHost>:<elasticsearchPort>
+```
+
+Example: 
+```sh
+node ../../../../scripts/es_archiver save custom_rules ".kibana",".siem-signal*"  --dir ../../../test/siem_cypress/es_archives --config ../../../../test/functional/config.js --es-url http://elastic:changeme@localhost:9220
+```
+
+Note that the command is going to create the folder if does not exist in the directory with the imported data.
+
+
 ## Running Tests Interactively
 
 Use the Cypress interactive test runner to develop and debug specific tests
@@ -210,30 +316,6 @@ cd x-pack/legacy/plugins/siem
 CYPRESS_baseUrl=http://localhost:5601 CYPRESS_ELASTICSEARCH_USERNAME=elastic CYPRESS_ELASTICSEARCH_PASSWORD=<password> yarn cypress:run
 ```
 
-## Running (Headless) Tests on the Command Line as a Jenkins execution
-
-To run (headless) tests as a Jenkins execution.
-
-1. First bootstrap kibana changes from the Kibana root directory:
-
-```sh
-yarn kbn bootstrap
-```
-
-2. Launch Cypress command line test runner:
-
-```sh 
-cd x-pack/legacy/plugins/siem
-yarn cypress:run-as-ci
-```
-
-Note that with this type of execution you don't need to have running a kibana and elasticsearch instance. This is because
- the command, as it would happen in the CI, will launch the instances. The elasticsearch instance will be fed with the data 
- placed in: `x-pack/test/siem_cypress/es_archives`.
- 
-As in this case we want to mimic a CI execution we want to execute the tests with the same set of data, this is why 
-in this case does not make sense to override Cypress environment variables.    
-
 ## Reporting
 
 When Cypress tests are run on the command line via `yarn cypress:run`,
@@ -280,4 +362,4 @@ target/kibana-siem/cypress/videos
 
 ## Linting 
 
-Optional linting rules for Cypress and linting setup can be found [here](https://github.com/cypress-io/eslint-plugin-cypress#usage)
\ No newline at end of file
+Optional linting rules for Cypress and linting setup can be found [here](https://github.com/cypress-io/eslint-plugin-cypress#usage)

From 93971dbfab74b39335115e8236741329486c4b79 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens <jloleysens@gmail.com>
Date: Fri, 10 Apr 2020 12:28:55 +0200
Subject: [PATCH 47/78] [Watcher] Preserve the watch active status after
 updates (#61999)

* Preserve the watch active status after updates

* Use route validation params to set isActive

* Fix Jest test

* Implement PR feedback

- Make the isActive flag required on the save watch endpoint
- Move the isActive state to base_watch and serialize from
  there.

* Fix Jest tests

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../watch_create_json.test.ts                 |  3 ++
 .../watch_create_threshold.test.tsx           |  8 +++++
 .../client_integration/watch_edit.test.ts     |  2 ++
 .../application/models/watch/base_watch.js    |  2 ++
 .../server/lib/elasticsearch_js_plugin.ts     |  4 +++
 .../routes/api/watch/register_save_route.ts   | 29 ++++++++-----------
 6 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts
index 2096c0dd61bd8..47de4548898cf 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts
@@ -108,6 +108,7 @@ describe('<JsonWatchEdit /> create route', () => {
               name: watch.name,
               type: watch.type,
               isNew: true,
+              isActive: true,
               actions: [
                 {
                   id: DEFAULT_LOGGING_ACTION_ID,
@@ -185,6 +186,7 @@ describe('<JsonWatchEdit /> create route', () => {
             id,
             type,
             isNew: true,
+            isActive: true,
             actions: [],
             watch: defaultWatchJson,
           };
@@ -246,6 +248,7 @@ describe('<JsonWatchEdit /> create route', () => {
             id,
             type,
             isNew: true,
+            isActive: true,
             actions: [],
             watch: defaultWatchJson,
           };
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx
index 943233d3c14ed..e5bdcbbfb82cf 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx
@@ -244,6 +244,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'logging_1',
@@ -314,6 +315,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'index_1',
@@ -376,6 +378,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'slack_1',
@@ -448,6 +451,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'email_1',
@@ -540,6 +544,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'webhook_1',
@@ -629,6 +634,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'jira_1',
@@ -709,6 +715,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [
               {
                 id: 'pagerduty_1',
@@ -772,6 +779,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
             name: WATCH_NAME,
             type: WATCH_TYPES.THRESHOLD,
             isNew: true,
+            isActive: true,
             actions: [],
             index: MATCH_INDICES,
             timeField: WATCH_TIME_FIELD,
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts
index 51285a5786b00..ced06562b1d20 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts
@@ -98,6 +98,7 @@ describe('<WatchEdit />', () => {
             name: EDITED_WATCH_NAME,
             type: watch.type,
             isNew: false,
+            isActive: true,
             actions: [
               {
                 id: DEFAULT_LOGGING_ACTION_ID,
@@ -191,6 +192,7 @@ describe('<WatchEdit />', () => {
             name: EDITED_WATCH_NAME,
             type,
             isNew: false,
+            isActive: true,
             actions: [],
             timeField,
             triggerIntervalSize,
diff --git a/x-pack/plugins/watcher/public/application/models/watch/base_watch.js b/x-pack/plugins/watcher/public/application/models/watch/base_watch.js
index 3fe4fb006d241..af2e45b35501e 100644
--- a/x-pack/plugins/watcher/public/application/models/watch/base_watch.js
+++ b/x-pack/plugins/watcher/public/application/models/watch/base_watch.js
@@ -32,6 +32,7 @@ export class BaseWatch {
     this.isSystemWatch = Boolean(get(props, 'isSystemWatch'));
     this.watchStatus = WatchStatus.fromUpstreamJson(get(props, 'watchStatus'));
     this.watchErrors = WatchErrors.fromUpstreamJson(get(props, 'watchErrors'));
+    this.isActive = this.watchStatus.isActive ?? true;
 
     const actions = get(props, 'actions', []);
     this.actions = actions.map(Action.fromUpstreamJson);
@@ -115,6 +116,7 @@ export class BaseWatch {
       name: this.name,
       type: this.type,
       isNew: this.isNew,
+      isActive: this.isActive,
       actions: map(this.actions, action => action.upstreamJson),
     };
   }
diff --git a/x-pack/plugins/watcher/server/lib/elasticsearch_js_plugin.ts b/x-pack/plugins/watcher/server/lib/elasticsearch_js_plugin.ts
index 240e93e160fe0..3cb8dfb623fac 100644
--- a/x-pack/plugins/watcher/server/lib/elasticsearch_js_plugin.ts
+++ b/x-pack/plugins/watcher/server/lib/elasticsearch_js_plugin.ts
@@ -174,6 +174,10 @@ export const elasticsearchJsPlugin = (Client: any, config: any, components: any)
         name: 'master_timeout',
         type: 'duration',
       },
+      active: {
+        name: 'active',
+        type: 'boolean',
+      },
     },
     url: {
       fmt: '/_watcher/watch/<%=id%>',
diff --git a/x-pack/plugins/watcher/server/routes/api/watch/register_save_route.ts b/x-pack/plugins/watcher/server/routes/api/watch/register_save_route.ts
index 61d167bb9bbcd..10ee0c4857862 100644
--- a/x-pack/plugins/watcher/server/routes/api/watch/register_save_route.ts
+++ b/x-pack/plugins/watcher/server/routes/api/watch/register_save_route.ts
@@ -5,7 +5,6 @@
  */
 
 import { schema } from '@kbn/config-schema';
-import { IScopedClusterClient } from 'kibana/server';
 import { i18n } from '@kbn/i18n';
 import { WATCH_TYPES } from '../../../../common/constants';
 import { serializeJsonWatch, serializeThresholdWatch } from '../../../../common/lib/serialization';
@@ -21,23 +20,11 @@ const bodySchema = schema.object(
   {
     type: schema.string(),
     isNew: schema.boolean(),
+    isActive: schema.boolean(),
   },
   { unknowns: 'allow' }
 );
 
-function fetchWatch(dataClient: IScopedClusterClient, watchId: string) {
-  return dataClient.callAsCurrentUser('watcher.getWatch', {
-    id: watchId,
-  });
-}
-
-function saveWatch(dataClient: IScopedClusterClient, id: string, body: any) {
-  return dataClient.callAsCurrentUser('watcher.putWatch', {
-    id,
-    body,
-  });
-}
-
 export function registerSaveRoute(deps: RouteDependencies) {
   deps.router.put(
     {
@@ -49,12 +36,16 @@ export function registerSaveRoute(deps: RouteDependencies) {
     },
     licensePreRoutingFactory(deps, async (ctx, request, response) => {
       const { id } = request.params;
-      const { type, isNew, ...watchConfig } = request.body;
+      const { type, isNew, isActive, ...watchConfig } = request.body;
+
+      const dataClient = ctx.watcher!.client;
 
       // For new watches, verify watch with the same ID doesn't already exist
       if (isNew) {
         try {
-          const existingWatch = await fetchWatch(ctx.watcher!.client, id);
+          const existingWatch = await dataClient.callAsCurrentUser('watcher.getWatch', {
+            id,
+          });
           if (existingWatch.found) {
             return response.conflict({
               body: {
@@ -92,7 +83,11 @@ export function registerSaveRoute(deps: RouteDependencies) {
       try {
         // Create new watch
         return response.ok({
-          body: await saveWatch(ctx.watcher!.client, id, serializedWatch),
+          body: await dataClient.callAsCurrentUser('watcher.putWatch', {
+            id,
+            active: isActive,
+            body: serializedWatch,
+          }),
         });
       } catch (e) {
         // Case: Error from Elasticsearch JS client

From d662cb5f4525e3a808900403f54f3c4f2c2c7097 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens <jloleysens@gmail.com>
Date: Fri, 10 Apr 2020 12:58:18 +0200
Subject: [PATCH 48/78] [ESUI] Move XJson Mode to src/plugins/es_ui_shared
 (#62758)

* Move XJson to x-pack/es_ui_shared

Also convert files to TS and clean up use of @ts-ignore

* Move console_lang to public

* Proper use of mocks

* Globally mock out .ace.worker.js modules

Having worker code exported in `public` of es_ui_shared poisoned
a lot of Jest tests with the need to mock out the ace worker.

Instead of adding mocks everywhere we handle the importing in
Jest by adding an entry to module mapper.

* Remove manual imports of mocks

* Delete es_ui_shared/public/mocks for now

* Put useXJson code in single place

* Import and instantiate xJsonMode

* Remove language mocks imports

Besides the fact that these paths are wrong these are no longer
needed because we mock at use Jest module mapper

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 src/dev/jest/config.js                        |  1 +
 .../jest/mocks/ace_worker_module_mock.js}     |  2 +-
 .../legacy/console_editor/editor_output.tsx   |  2 +-
 .../send_request_to_es.ts                     |  2 +-
 .../__tests__/output_tokenization.test.js     |  1 +
 .../mode/input_highlight_rules.js             |  2 +-
 .../mode/output_highlight_rules.js            |  2 +-
 .../models/legacy_core_editor/mode/script.js  |  2 +-
 .../__tests__/sense_editor.test.js            |  2 +-
 .../models/sense_editor/sense_editor.ts       |  2 +-
 src/plugins/console/public/lib/utils/index.ts |  5 +--
 .../console_lang/ace/modes/index.ts}          |  2 +-
 .../elasticsearch_sql_highlight_rules.ts      |  0
 .../ace/modes/lexer_rules/index.ts}           |  0
 .../lexer_rules/script_highlight_rules.ts}    |  4 +--
 .../lexer_rules/x_json_highlight_rules.ts}    | 12 +++----
 .../console_lang/ace/modes/x_json/index.ts    | 19 ++++++++++
 .../ace/modes/x_json/worker/index.ts          | 26 ++++++++++++++
 .../ace/modes/x_json/worker/worker.d.ts       | 25 +++++++++++++
 .../modes/x_json/worker/x_json.ace.worker.js  |  0
 .../console_lang/ace/modes/x_json/x_json.ts}  | 35 ++++++++++++++++---
 .../{ => public}/console_lang/index.ts        |  3 ++
 .../{ => public}/console_lang/lib/index.ts    |  0
 .../json_xjson_translation_tools.test.ts      |  0
 .../__tests__/utils_string_collapsing.txt     |  0
 .../__tests__/utils_string_expanding.txt      |  0
 .../lib/json_xjson_translation_tools/index.ts |  0
 src/plugins/es_ui_shared/public/index.ts      | 11 ++++++
 .../static/ace_x_json/hooks/index.ts          | 20 +++++++++++
 .../ace_x_json/hooks/use_x_json.ts}           | 26 ++++++++------
 x-pack/dev-tools/jest/create_jest_config.js   |  1 +
 .../console_lang/ace/modes/index.ts           |  7 ----
 .../console_lang/ace/modes/x_json/index.ts    |  7 ----
 .../ace/modes/x_json/worker/index.ts          | 13 -------
 .../ace/modes/x_json/worker/worker.d.ts       | 12 -------
 .../console_lang/ace/modes/x_json/x_json.ts   | 34 ------------------
 .../es_ui_shared/console_lang/index.ts        |  7 ----
 .../es_ui_shared/console_lang/mocks.ts        |  9 -----
 .../components/custom_hooks/index.ts          |  1 -
 .../custom_hooks/use_x_json_mode.ts           | 26 --------------
 .../create_analytics_advanced_editor.tsx      |  5 ++-
 .../use_create_analytics_form/reducer.ts      |  2 +-
 .../ml_job_editor/ml_job_editor.tsx           |  5 ++-
 x-pack/plugins/ml/shared_imports.ts           |  5 ++-
 .../public/application/editor/editor.test.tsx |  2 --
 .../public/application/editor/init_editor.ts  |  2 +-
 .../utils/check_for_json_errors.ts            |  2 +-
 .../public/app/hooks/use_x_json_mode.ts       | 20 -----------
 .../step_define/step_define_form.tsx          |  4 ++-
 .../transform/public/shared_imports.ts        |  4 +--
 .../builtin_action_types/es_index.tsx         |  2 +-
 .../public/application/lib/use_x_json_mode.ts | 25 -------------
 .../watch_create_json.test.ts                 |  2 --
 .../watch_create_threshold.test.tsx           |  2 --
 .../client_integration/watch_edit.test.ts     |  1 -
 .../client_integration/watch_list.test.ts     |  1 -
 .../client_integration/watch_status.test.ts   |  1 -
 .../json_watch_edit/json_watch_edit_form.tsx  |  3 +-
 .../json_watch_edit_simulate.tsx              |  2 +-
 .../json_watch_edit/use_x_json_mode.ts        | 24 -------------
 .../public/application/shared_imports.ts      |  2 ++
 61 files changed, 193 insertions(+), 246 deletions(-)
 rename src/{plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts => dev/jest/mocks/ace_worker_module_mock.js} (94%)
 rename src/plugins/es_ui_shared/{console_lang/ace/modes/index.js => public/console_lang/ace/modes/index.ts} (94%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/ace/modes/lexer_rules/elasticsearch_sql_highlight_rules.ts (100%)
 rename src/plugins/es_ui_shared/{console_lang/ace/modes/lexer_rules/index.js => public/console_lang/ace/modes/lexer_rules/index.ts} (100%)
 rename src/plugins/es_ui_shared/{console_lang/ace/modes/lexer_rules/script_highlight_rules.js => public/console_lang/ace/modes/lexer_rules/script_highlight_rules.ts} (97%)
 rename src/plugins/es_ui_shared/{console_lang/ace/modes/lexer_rules/x_json_highlight_rules.js => public/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.ts} (94%)
 create mode 100644 src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/index.ts
 create mode 100644 src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/index.ts
 create mode 100644 src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/worker.d.ts
 rename x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.js => src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/x_json.ace.worker.js (100%)
 rename src/plugins/es_ui_shared/{console_lang/ace/modes/x_json/x_json_mode.ts => public/console_lang/ace/modes/x_json/x_json.ts} (61%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/index.ts (92%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/lib/index.ts (100%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/lib/json_xjson_translation_tools/__tests__/json_xjson_translation_tools.test.ts (100%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_collapsing.txt (100%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_expanding.txt (100%)
 rename src/plugins/es_ui_shared/{ => public}/console_lang/lib/json_xjson_translation_tools/index.ts (100%)
 create mode 100644 src/plugins/es_ui_shared/static/ace_x_json/hooks/index.ts
 rename src/plugins/es_ui_shared/{console_lang/ace/modes/index.d.ts => static/ace_x_json/hooks/use_x_json.ts} (60%)
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.d.ts
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/index.ts
 delete mode 100644 x-pack/plugins/es_ui_shared/console_lang/mocks.ts
 delete mode 100644 x-pack/plugins/ml/public/application/components/custom_hooks/use_x_json_mode.ts
 delete mode 100644 x-pack/plugins/transform/public/app/hooks/use_x_json_mode.ts
 delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/lib/use_x_json_mode.ts
 delete mode 100644 x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts

diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js
index a941735c7840e..7da14e0dfe51b 100644
--- a/src/dev/jest/config.js
+++ b/src/dev/jest/config.js
@@ -62,6 +62,7 @@ export default {
     '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
       '<rootDir>/src/dev/jest/mocks/file_mock.js',
     '\\.(css|less|scss)$': '<rootDir>/src/dev/jest/mocks/style_mock.js',
+    '\\.ace\\.worker.js$': '<rootDir>/src/dev/jest/mocks/ace_worker_module_mock.js',
   },
   setupFiles: [
     '<rootDir>/src/dev/jest/setup/babel_polyfill.js',
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts b/src/dev/jest/mocks/ace_worker_module_mock.js
similarity index 94%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts
rename to src/dev/jest/mocks/ace_worker_module_mock.js
index caa7b518b8b66..9d267f494f8bf 100644
--- a/src/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts
+++ b/src/dev/jest/mocks/ace_worker_module_mock.js
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-export { XJsonMode } from './x_json_mode';
+module.exports = '';
diff --git a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor_output.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor_output.tsx
index 36d90bb6bff1a..8510aaebfaa1e 100644
--- a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor_output.tsx
+++ b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor_output.tsx
@@ -20,7 +20,7 @@
 import { EuiScreenReaderOnly } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import React, { useEffect, useRef } from 'react';
-import { expandLiteralStrings } from '../../../../../../../es_ui_shared/console_lang/lib';
+import { expandLiteralStrings } from '../../../../../../../es_ui_shared/public';
 import {
   useEditorReadContext,
   useRequestReadContext,
diff --git a/src/plugins/console/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
index 102f90a9feb6f..cfbd5691bc22b 100644
--- a/src/plugins/console/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
+++ b/src/plugins/console/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts
@@ -18,7 +18,7 @@
  */
 
 import { extractDeprecationMessages } from '../../../lib/utils';
-import { collapseLiteralStrings } from '../../../../../es_ui_shared/console_lang/lib';
+import { collapseLiteralStrings } from '../../../../../es_ui_shared/public';
 // @ts-ignore
 import * as es from '../../../lib/es/es';
 import { BaseResponseType } from '../../../types';
diff --git a/src/plugins/console/public/application/models/legacy_core_editor/__tests__/output_tokenization.test.js b/src/plugins/console/public/application/models/legacy_core_editor/__tests__/output_tokenization.test.js
index 6a93d007a6cdc..5c86b0a1d2092 100644
--- a/src/plugins/console/public/application/models/legacy_core_editor/__tests__/output_tokenization.test.js
+++ b/src/plugins/console/public/application/models/legacy_core_editor/__tests__/output_tokenization.test.js
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import '../legacy_core_editor.test.mocks';
 const $ = require('jquery');
 import RowParser from '../../../../lib/row_parser';
 import ace from 'brace';
diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.js
index 2c1b30f806f95..29f192f4ea858 100644
--- a/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.js
+++ b/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.js
@@ -18,7 +18,7 @@
  */
 
 const ace = require('brace');
-import { addXJsonToRules } from '../../../../../../es_ui_shared/console_lang';
+import { addXJsonToRules } from '../../../../../../es_ui_shared/public';
 
 export function addEOL(tokens, reg, nextIfEOL, normalNext) {
   if (typeof reg === 'object') {
diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.js
index e27222ebd65e9..c9d538ab6ceb1 100644
--- a/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.js
+++ b/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.js
@@ -19,7 +19,7 @@
 
 const ace = require('brace');
 import 'brace/mode/json';
-import { addXJsonToRules } from '../../../../../../es_ui_shared/console_lang';
+import { addXJsonToRules } from '../../../../../../es_ui_shared/public';
 
 const oop = ace.acequire('ace/lib/oop');
 const JsonHighlightRules = ace.acequire('ace/mode/json_highlight_rules').JsonHighlightRules;
diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/script.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/script.js
index 13ae329380221..89adea8921c07 100644
--- a/src/plugins/console/public/application/models/legacy_core_editor/mode/script.js
+++ b/src/plugins/console/public/application/models/legacy_core_editor/mode/script.js
@@ -18,7 +18,7 @@
  */
 
 import ace from 'brace';
-import { ScriptHighlightRules } from '../../../../../../es_ui_shared/console_lang';
+import { ScriptHighlightRules } from '../../../../../../es_ui_shared/public';
 
 const oop = ace.acequire('ace/lib/oop');
 const TextMode = ace.acequire('ace/mode/text').Mode;
diff --git a/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js b/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js
index 63f97345bc9ff..6afc03df13b4c 100644
--- a/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js
+++ b/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js
@@ -22,7 +22,7 @@ import $ from 'jquery';
 import _ from 'lodash';
 
 import { create } from '../create';
-import { collapseLiteralStrings } from '../../../../../../es_ui_shared/console_lang/lib';
+import { collapseLiteralStrings } from '../../../../../../es_ui_shared/public';
 const editorInput1 = require('./editor_input1.txt');
 
 describe('Editor', () => {
diff --git a/src/plugins/console/public/application/models/sense_editor/sense_editor.ts b/src/plugins/console/public/application/models/sense_editor/sense_editor.ts
index b1444bdf2bbab..9bcd3a6872196 100644
--- a/src/plugins/console/public/application/models/sense_editor/sense_editor.ts
+++ b/src/plugins/console/public/application/models/sense_editor/sense_editor.ts
@@ -19,7 +19,7 @@
 
 import _ from 'lodash';
 import RowParser from '../../../lib/row_parser';
-import { collapseLiteralStrings } from '../../../../../es_ui_shared/console_lang/lib';
+import { collapseLiteralStrings } from '../../../../../es_ui_shared/public';
 import * as utils from '../../../lib/utils';
 
 // @ts-ignore
diff --git a/src/plugins/console/public/lib/utils/index.ts b/src/plugins/console/public/lib/utils/index.ts
index f66c952dd3af7..0ebea0f9d4055 100644
--- a/src/plugins/console/public/lib/utils/index.ts
+++ b/src/plugins/console/public/lib/utils/index.ts
@@ -18,10 +18,7 @@
  */
 
 import _ from 'lodash';
-import {
-  expandLiteralStrings,
-  collapseLiteralStrings,
-} from '../../../../es_ui_shared/console_lang/lib';
+import { expandLiteralStrings, collapseLiteralStrings } from '../../../../es_ui_shared/public';
 
 export function textFromRequest(request: any) {
   let data = request.data;
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/index.js b/src/plugins/es_ui_shared/public/console_lang/ace/modes/index.ts
similarity index 94%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/index.js
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/index.ts
index 955f23116f659..f9e016c5078af 100644
--- a/src/plugins/es_ui_shared/console_lang/ace/modes/index.js
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/index.ts
@@ -24,4 +24,4 @@ export {
   addXJsonToRules,
 } from './lexer_rules';
 
-export { XJsonMode, installXJsonMode } from './x_json';
+export { installXJsonMode, XJsonMode } from './x_json';
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/elasticsearch_sql_highlight_rules.ts b/src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/elasticsearch_sql_highlight_rules.ts
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/elasticsearch_sql_highlight_rules.ts
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/elasticsearch_sql_highlight_rules.ts
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/index.js b/src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/index.ts
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/index.js
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/index.ts
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/script_highlight_rules.js b/src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/script_highlight_rules.ts
similarity index 97%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/script_highlight_rules.js
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/script_highlight_rules.ts
index b3999c76493c0..4b2e965276a3c 100644
--- a/src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/script_highlight_rules.js
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/script_highlight_rules.ts
@@ -17,13 +17,13 @@
  * under the License.
  */
 
-const ace = require('brace');
+import ace from 'brace';
 const oop = ace.acequire('ace/lib/oop');
 const { TextHighlightRules } = ace.acequire('ace/mode/text_highlight_rules');
 const painlessKeywords =
   'def|int|long|byte|String|float|double|char|null|if|else|while|do|for|continue|break|new|try|catch|throw|this|instanceof|return|ctx';
 
-export function ScriptHighlightRules() {
+export function ScriptHighlightRules(this: any) {
   this.name = 'ScriptHighlightRules';
   this.$rules = {
     start: [
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.js b/src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.ts
similarity index 94%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.js
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.ts
index 14323b9320330..3663b92d92a6f 100644
--- a/src/plugins/es_ui_shared/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.js
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/lexer_rules/x_json_highlight_rules.ts
@@ -22,14 +22,14 @@ import ace from 'brace';
 import 'brace/mode/json';
 
 import { ElasticsearchSqlHighlightRules } from './elasticsearch_sql_highlight_rules';
-const { ScriptHighlightRules } = require('./script_highlight_rules');
+import { ScriptHighlightRules } from './script_highlight_rules';
 
 const { JsonHighlightRules } = ace.acequire('ace/mode/json_highlight_rules');
 const oop = ace.acequire('ace/lib/oop');
 
-const jsonRules = function(root) {
+const jsonRules = function(root: any) {
   root = root ? root : 'json';
-  const rules = {};
+  const rules: any = {};
   const xJsonRules = [
     {
       token: [
@@ -135,7 +135,7 @@ const jsonRules = function(root) {
       merge: false,
       push: true,
     },
-  ].concat(xJsonRules);
+  ].concat(xJsonRules as any);
 
   rules.string_literal = [
     {
@@ -151,7 +151,7 @@ const jsonRules = function(root) {
   return rules;
 };
 
-export function XJsonHighlightRules() {
+export function XJsonHighlightRules(this: any) {
   this.$rules = {
     ...jsonRules('start'),
   };
@@ -175,7 +175,7 @@ export function XJsonHighlightRules() {
 
 oop.inherits(XJsonHighlightRules, JsonHighlightRules);
 
-export function addToRules(otherRules, embedUnder) {
+export function addToRules(otherRules: any, embedUnder: any) {
   otherRules.$rules = _.defaultsDeep(otherRules.$rules, jsonRules(embedUnder));
   otherRules.embedRules(ScriptHighlightRules, 'script-', [
     {
diff --git a/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/index.ts b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/index.ts
new file mode 100644
index 0000000000000..6fd819bb4e9eb
--- /dev/null
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/index.ts
@@ -0,0 +1,19 @@
+/*
+ * 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 { installXJsonMode, XJsonMode } from './x_json';
diff --git a/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/index.ts b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/index.ts
new file mode 100644
index 0000000000000..0f884765be05e
--- /dev/null
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/index.ts
@@ -0,0 +1,26 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// @ts-ignore
+import src from '!!raw-loader!./x_json.ace.worker.js';
+
+export const workerModule = {
+  id: 'ace/mode/json_worker',
+  src,
+};
diff --git a/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/worker.d.ts b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/worker.d.ts
new file mode 100644
index 0000000000000..d2363a2610689
--- /dev/null
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/worker.d.ts
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// Satisfy TS's requirements that the module be declared per './index.ts'.
+declare module '!!raw-loader!./worker.js' {
+  const content: string;
+  // eslint-disable-next-line import/no-default-export
+  export default content;
+}
diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.js b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/x_json.ace.worker.js
similarity index 100%
rename from x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.js
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/worker/x_json.ace.worker.js
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json_mode.ts b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/x_json.ts
similarity index 61%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json_mode.ts
rename to src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/x_json.ts
index 9f804c29a5d27..9fbfedba1d23f 100644
--- a/src/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json_mode.ts
+++ b/src/plugins/es_ui_shared/public/console_lang/ace/modes/x_json/x_json.ts
@@ -18,23 +18,50 @@
  */
 
 import ace from 'brace';
-
 import { XJsonHighlightRules } from '../index';
+import { workerModule } from './worker';
+
+const { WorkerClient } = ace.acequire('ace/worker/worker_client');
 
 const oop = ace.acequire('ace/lib/oop');
+
 const { Mode: JSONMode } = ace.acequire('ace/mode/json');
 const { Tokenizer: AceTokenizer } = ace.acequire('ace/tokenizer');
 const { MatchingBraceOutdent } = ace.acequire('ace/mode/matching_brace_outdent');
 const { CstyleBehaviour } = ace.acequire('ace/mode/behaviour/cstyle');
 const { FoldMode: CStyleFoldMode } = ace.acequire('ace/mode/folding/cstyle');
 
-export function XJsonMode(this: any) {
-  const ruleset: any = new XJsonHighlightRules();
+const XJsonMode: any = function XJsonMode(this: any) {
+  const ruleset: any = new (XJsonHighlightRules as any)();
   ruleset.normalizeRules();
   this.$tokenizer = new AceTokenizer(ruleset.getRules());
   this.$outdent = new MatchingBraceOutdent();
   this.$behaviour = new CstyleBehaviour();
   this.foldingRules = new CStyleFoldMode();
-}
+};
 
 oop.inherits(XJsonMode, JSONMode);
+
+// Then clobber `createWorker` method to install our worker source. Per ace's wiki: https://github.com/ajaxorg/ace/wiki/Syntax-validation
+(XJsonMode.prototype as any).createWorker = function(session: ace.IEditSession) {
+  const xJsonWorker = new WorkerClient(['ace'], workerModule, 'JsonWorker');
+
+  xJsonWorker.attachToDocument(session.getDocument());
+
+  xJsonWorker.on('annotate', function(e: { data: any }) {
+    session.setAnnotations(e.data);
+  });
+
+  xJsonWorker.on('terminate', function() {
+    session.clearAnnotations();
+  });
+
+  return xJsonWorker;
+};
+
+export { XJsonMode };
+
+export function installXJsonMode(editor: ace.Editor) {
+  const session = editor.getSession();
+  session.setMode(new XJsonMode());
+}
diff --git a/src/plugins/es_ui_shared/console_lang/index.ts b/src/plugins/es_ui_shared/public/console_lang/index.ts
similarity index 92%
rename from src/plugins/es_ui_shared/console_lang/index.ts
rename to src/plugins/es_ui_shared/public/console_lang/index.ts
index a4958911af412..7d83191569622 100644
--- a/src/plugins/es_ui_shared/console_lang/index.ts
+++ b/src/plugins/es_ui_shared/public/console_lang/index.ts
@@ -26,4 +26,7 @@ export {
   XJsonHighlightRules,
   addXJsonToRules,
   XJsonMode,
+  installXJsonMode,
 } from './ace/modes';
+
+export { expandLiteralStrings, collapseLiteralStrings } from './lib';
diff --git a/src/plugins/es_ui_shared/console_lang/lib/index.ts b/src/plugins/es_ui_shared/public/console_lang/lib/index.ts
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/lib/index.ts
rename to src/plugins/es_ui_shared/public/console_lang/lib/index.ts
diff --git a/src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/__tests__/json_xjson_translation_tools.test.ts b/src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/__tests__/json_xjson_translation_tools.test.ts
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/__tests__/json_xjson_translation_tools.test.ts
rename to src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/__tests__/json_xjson_translation_tools.test.ts
diff --git a/src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_collapsing.txt b/src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_collapsing.txt
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_collapsing.txt
rename to src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_collapsing.txt
diff --git a/src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_expanding.txt b/src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_expanding.txt
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_expanding.txt
rename to src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/__tests__/utils_string_expanding.txt
diff --git a/src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/index.ts b/src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/index.ts
similarity index 100%
rename from src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools/index.ts
rename to src/plugins/es_ui_shared/public/console_lang/lib/json_xjson_translation_tools/index.ts
diff --git a/src/plugins/es_ui_shared/public/index.ts b/src/plugins/es_ui_shared/public/index.ts
index 6db6248f4c68f..a0371bf351193 100644
--- a/src/plugins/es_ui_shared/public/index.ts
+++ b/src/plugins/es_ui_shared/public/index.ts
@@ -36,6 +36,17 @@ export { indices } from './indices';
 
 export { useUIAceKeyboardMode } from './use_ui_ace_keyboard_mode';
 
+export {
+  installXJsonMode,
+  XJsonMode,
+  ElasticsearchSqlHighlightRules,
+  addXJsonToRules,
+  ScriptHighlightRules,
+  XJsonHighlightRules,
+  collapseLiteralStrings,
+  expandLiteralStrings,
+} from './console_lang';
+
 /** dummy plugin, we just want esUiShared to have its own bundle */
 export function plugin() {
   return new (class EsUiSharedPlugin {
diff --git a/src/plugins/es_ui_shared/static/ace_x_json/hooks/index.ts b/src/plugins/es_ui_shared/static/ace_x_json/hooks/index.ts
new file mode 100644
index 0000000000000..1d2c33a9f0f47
--- /dev/null
+++ b/src/plugins/es_ui_shared/static/ace_x_json/hooks/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export { useXJsonMode } from './use_x_json';
diff --git a/src/plugins/es_ui_shared/console_lang/ace/modes/index.d.ts b/src/plugins/es_ui_shared/static/ace_x_json/hooks/use_x_json.ts
similarity index 60%
rename from src/plugins/es_ui_shared/console_lang/ace/modes/index.d.ts
rename to src/plugins/es_ui_shared/static/ace_x_json/hooks/use_x_json.ts
index 06c9f9a51ea68..2b0bf0c8a3a7c 100644
--- a/src/plugins/es_ui_shared/console_lang/ace/modes/index.d.ts
+++ b/src/plugins/es_ui_shared/static/ace_x_json/hooks/use_x_json.ts
@@ -17,16 +17,22 @@
  * under the License.
  */
 
-import { Editor } from 'brace';
+import { useState } from 'react';
+import { XJsonMode, collapseLiteralStrings, expandLiteralStrings } from '../../../public';
 
-export declare const ElasticsearchSqlHighlightRules: FunctionConstructor;
-export declare const ScriptHighlightRules: FunctionConstructor;
-export declare const XJsonHighlightRules: FunctionConstructor;
+const xJsonMode = new XJsonMode();
 
-export declare const XJsonMode: FunctionConstructor;
+export const useXJsonMode = (json: Record<string, any> | string | null) => {
+  const [xJson, setXJson] = useState(() =>
+    json === null
+      ? ''
+      : expandLiteralStrings(typeof json === 'string' ? json : JSON.stringify(json, null, 2))
+  );
 
-/**
- * @param otherRules Another Ace ruleset
- * @param embedUnder The state name under which the rules will be embedded. Defaults to "json".
- */
-export declare const addXJsonToRules: (otherRules: any, embedUnder?: string) => void;
+  return {
+    xJson,
+    setXJson,
+    xJsonMode,
+    convertToJson: collapseLiteralStrings,
+  };
+};
diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js
index 1f4311ae9bcf6..3068cdd0daa5b 100644
--- a/x-pack/dev-tools/jest/create_jest_config.js
+++ b/x-pack/dev-tools/jest/create_jest_config.js
@@ -28,6 +28,7 @@ export function createJestConfig({ kibanaDirectory, xPackKibanaDirectory }) {
       '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': fileMockPath,
       '\\.module.(css|scss)$': `${kibanaDirectory}/src/dev/jest/mocks/css_module_mock.js`,
       '\\.(css|less|scss)$': `${kibanaDirectory}/src/dev/jest/mocks/style_mock.js`,
+      '\\.ace\\.worker.js$': `${kibanaDirectory}/src/dev/jest/mocks/ace_worker_module_mock.js`,
       '^test_utils/enzyme_helpers': `${xPackKibanaDirectory}/test_utils/enzyme_helpers.tsx`,
       '^test_utils/find_test_subject': `${xPackKibanaDirectory}/test_utils/find_test_subject.ts`,
       '^test_utils/stub_web_worker': `${xPackKibanaDirectory}/test_utils/stub_web_worker.ts`,
diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts
deleted file mode 100644
index ae3c9962ecadb..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { installXJsonMode, XJsonMode } from './x_json';
diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts
deleted file mode 100644
index ae3c9962ecadb..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { installXJsonMode, XJsonMode } from './x_json';
diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts
deleted file mode 100644
index 0e40fd335dd31..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-// @ts-ignore
-import src from '!!raw-loader!./worker.js';
-
-export const workerModule = {
-  id: 'ace/mode/json_worker',
-  src,
-};
diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.d.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.d.ts
deleted file mode 100644
index 4ebad4f2ef91c..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.d.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-// Satisfy TS's requirements that the module be declared per './index.ts'.
-declare module '!!raw-loader!./worker.js' {
-  const content: string;
-  // eslint-disable-next-line import/no-default-export
-  export default content;
-}
diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts
deleted file mode 100644
index bfeca045bea02..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import ace from 'brace';
-import { XJsonMode } from '../../../../../../../src/plugins/es_ui_shared/console_lang';
-import { workerModule } from './worker';
-const { WorkerClient } = ace.acequire('ace/worker/worker_client');
-
-// Then clobber `createWorker` method to install our worker source. Per ace's wiki: https://github.com/ajaxorg/ace/wiki/Syntax-validation
-(XJsonMode.prototype as any).createWorker = function(session: ace.IEditSession) {
-  const xJsonWorker = new WorkerClient(['ace'], workerModule, 'JsonWorker');
-
-  xJsonWorker.attachToDocument(session.getDocument());
-
-  xJsonWorker.on('annotate', function(e: { data: any }) {
-    session.setAnnotations(e.data);
-  });
-
-  xJsonWorker.on('terminate', function() {
-    session.clearAnnotations();
-  });
-
-  return xJsonWorker;
-};
-
-export { XJsonMode };
-
-export function installXJsonMode(editor: ace.Editor) {
-  const session = editor.getSession();
-  session.setMode(new (XJsonMode as any)());
-}
diff --git a/x-pack/plugins/es_ui_shared/console_lang/index.ts b/x-pack/plugins/es_ui_shared/console_lang/index.ts
deleted file mode 100644
index b5fe3a554e34d..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export { XJsonMode, installXJsonMode } from './ace/modes';
diff --git a/x-pack/plugins/es_ui_shared/console_lang/mocks.ts b/x-pack/plugins/es_ui_shared/console_lang/mocks.ts
deleted file mode 100644
index 68480282ddc03..0000000000000
--- a/x-pack/plugins/es_ui_shared/console_lang/mocks.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-jest.mock('./ace/modes/x_json/worker', () => ({
-  workerModule: { id: 'ace/mode/json_worker', src: '' },
-}));
diff --git a/x-pack/plugins/ml/public/application/components/custom_hooks/index.ts b/x-pack/plugins/ml/public/application/components/custom_hooks/index.ts
index dfd74d8970cb4..ffead802bd6f9 100644
--- a/x-pack/plugins/ml/public/application/components/custom_hooks/index.ts
+++ b/x-pack/plugins/ml/public/application/components/custom_hooks/index.ts
@@ -5,4 +5,3 @@
  */
 
 export { usePartialState } from './use_partial_state';
-export { useXJsonMode, xJsonMode } from './use_x_json_mode';
diff --git a/x-pack/plugins/ml/public/application/components/custom_hooks/use_x_json_mode.ts b/x-pack/plugins/ml/public/application/components/custom_hooks/use_x_json_mode.ts
deleted file mode 100644
index c979632db54d6..0000000000000
--- a/x-pack/plugins/ml/public/application/components/custom_hooks/use_x_json_mode.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { useState } from 'react';
-import {
-  collapseLiteralStrings,
-  expandLiteralStrings,
-  XJsonMode,
-} from '../../../../shared_imports';
-
-// @ts-ignore
-export const xJsonMode = new XJsonMode();
-
-export const useXJsonMode = (json: string) => {
-  const [xJson, setXJson] = useState(expandLiteralStrings(json));
-
-  return {
-    xJson,
-    setXJson,
-    xJsonMode,
-    convertToJson: collapseLiteralStrings,
-  };
-};
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx
index a3e5da5e2d039..cef03cc0d0c76 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx
+++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx
@@ -18,8 +18,11 @@ import {
 
 import { i18n } from '@kbn/i18n';
 
+import { XJsonMode } from '../../../../../../../shared_imports';
+
+const xJsonMode = new XJsonMode();
+
 import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form';
-import { xJsonMode } from '../../../../../components/custom_hooks';
 
 export const CreateAnalyticsAdvancedEditor: FC<CreateAnalyticsFormProps> = ({ actions, state }) => {
   const { setAdvancedEditorRawString, setFormState } = actions;
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts
index ded6e50947035..d55eb14a20e29 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts
+++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts
@@ -11,7 +11,7 @@ import numeral from '@elastic/numeral';
 import { isEmpty } from 'lodash';
 import { isValidIndexName } from '../../../../../../../common/util/es_utils';
 
-import { collapseLiteralStrings } from '../../../../../../../../../../src/plugins/es_ui_shared/console_lang/lib/json_xjson_translation_tools';
+import { collapseLiteralStrings } from '../../../../../../../../../../src/plugins/es_ui_shared/public';
 
 import { Action, ACTION } from './actions';
 import { getInitialState, getJobConfigFromFormState, State } from './state';
diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/ml_job_editor/ml_job_editor.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/ml_job_editor/ml_job_editor.tsx
index 0633c62f754e0..c10212ee31564 100644
--- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/ml_job_editor/ml_job_editor.tsx
+++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/ml_job_editor/ml_job_editor.tsx
@@ -7,10 +7,9 @@
 import React, { FC } from 'react';
 
 import { EuiCodeEditor, EuiCodeEditorProps } from '@elastic/eui';
-import { expandLiteralStrings } from '../../../../../../shared_imports';
-import { xJsonMode } from '../../../../components/custom_hooks';
+import { expandLiteralStrings, XJsonMode } from '../../../../../../shared_imports';
 
-export const ML_EDITOR_MODE = { TEXT: 'text', JSON: 'json', XJSON: xJsonMode };
+export const ML_EDITOR_MODE = { TEXT: 'text', JSON: 'json', XJSON: new XJsonMode() };
 
 interface MlJobEditorProps {
   value: string;
diff --git a/x-pack/plugins/ml/shared_imports.ts b/x-pack/plugins/ml/shared_imports.ts
index 94ce8c82f1d95..a82ed5387818d 100644
--- a/x-pack/plugins/ml/shared_imports.ts
+++ b/x-pack/plugins/ml/shared_imports.ts
@@ -4,9 +4,8 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-export { XJsonMode } from '../../../src/plugins/es_ui_shared/console_lang/ace/modes/x_json';
-
 export {
+  XJsonMode,
   collapseLiteralStrings,
   expandLiteralStrings,
-} from '../../../src/plugins/es_ui_shared/console_lang/lib';
+} from '../../../src/plugins/es_ui_shared/public';
diff --git a/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx b/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx
index ad56b3957eb74..e56fc79156666 100644
--- a/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx
+++ b/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx
@@ -6,8 +6,6 @@
 import 'brace';
 import 'brace/mode/json';
 
-import '../../../../es_ui_shared/console_lang/mocks';
-
 import { registerTestBed } from '../../../../../test_utils';
 import { Editor, Props } from '.';
 
diff --git a/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts b/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts
index 6f19ce12eb639..3ad92531e4367 100644
--- a/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts
+++ b/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts
@@ -5,7 +5,7 @@
  */
 
 import ace from 'brace';
-import { installXJsonMode } from '../../../../es_ui_shared/console_lang';
+import { installXJsonMode } from '../../../../../../src/plugins/es_ui_shared/public';
 
 export function initializeEditor({
   el,
diff --git a/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts b/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts
index 99687de0f1440..58a62c4636c25 100644
--- a/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts
+++ b/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts
@@ -4,7 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { collapseLiteralStrings } from '../../../../../../src/plugins/es_ui_shared/console_lang/lib';
+import { collapseLiteralStrings } from '../../../../../../src/plugins/es_ui_shared/public';
 
 export function checkForParseErrors(json: string) {
   const sanitizedJson = collapseLiteralStrings(json);
diff --git a/x-pack/plugins/transform/public/app/hooks/use_x_json_mode.ts b/x-pack/plugins/transform/public/app/hooks/use_x_json_mode.ts
deleted file mode 100644
index 1017ce198ff29..0000000000000
--- a/x-pack/plugins/transform/public/app/hooks/use_x_json_mode.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { useState } from 'react';
-import { collapseLiteralStrings, expandLiteralStrings, XJsonMode } from '../../shared_imports';
-
-export const xJsonMode = new XJsonMode();
-
-export const useXJsonMode = (json: string) => {
-  const [xJson, setXJson] = useState(expandLiteralStrings(json));
-
-  return {
-    xJson,
-    setXJson,
-    xJsonMode,
-    convertToJson: collapseLiteralStrings,
-  };
-};
diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx
index 5e0eb7ee08361..320e405b5d437 100644
--- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx
+++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx
@@ -33,11 +33,12 @@ import {
   QueryStringInput,
 } from '../../../../../../../../../src/plugins/data/public';
 
+import { useXJsonMode } from '../../../../../../../../../src/plugins/es_ui_shared/static/ace_x_json/hooks';
+
 import { PivotPreview } from '../../../../components/pivot_preview';
 
 import { useDocumentationLinks } from '../../../../hooks/use_documentation_links';
 import { SavedSearchQuery, SearchItems } from '../../../../hooks/use_search_items';
-import { useXJsonMode, xJsonMode } from '../../../../hooks/use_x_json_mode';
 import { useToastNotifications } from '../../../../app_dependencies';
 import { TransformPivotConfig } from '../../../../common';
 import { dictionaryToArray, Dictionary } from '../../../../../../common/types/common';
@@ -432,6 +433,7 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
     convertToJson,
     setXJson: setAdvancedEditorConfig,
     xJson: advancedEditorConfig,
+    xJsonMode,
   } = useXJsonMode(stringifiedPivotConfig);
 
   useEffect(() => {
diff --git a/x-pack/plugins/transform/public/shared_imports.ts b/x-pack/plugins/transform/public/shared_imports.ts
index 8eb42ad677c0f..494b6db6aafe0 100644
--- a/x-pack/plugins/transform/public/shared_imports.ts
+++ b/x-pack/plugins/transform/public/shared_imports.ts
@@ -5,11 +5,11 @@
  */
 
 export { createSavedSearchesLoader } from '../../../../src/plugins/discover/public';
-export { XJsonMode } from '../../es_ui_shared/console_lang/ace/modes/x_json';
 export {
+  XJsonMode,
   collapseLiteralStrings,
   expandLiteralStrings,
-} from '../../../../src/plugins/es_ui_shared/console_lang/lib';
+} from '../../../../src/plugins/es_ui_shared/public';
 
 export {
   UseRequestConfig,
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx
index 9bd6a39d216e3..15f68e6a9f441 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index.tsx
@@ -17,6 +17,7 @@ import {
 } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { i18n } from '@kbn/i18n';
+import { useXJsonMode } from '../../../../../../../src/plugins/es_ui_shared/static/ace_x_json/hooks';
 import {
   ActionTypeModel,
   ActionConnectorFieldsProps,
@@ -31,7 +32,6 @@ import {
   getIndexOptions,
   getIndexPatterns,
 } from '../../../common/index_controls';
-import { useXJsonMode } from '../../lib/use_x_json_mode';
 import { AddMessageVariables } from '../add_message_variables';
 
 export function getActionType(): ActionTypeModel {
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/use_x_json_mode.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/use_x_json_mode.ts
deleted file mode 100644
index b677924724ffe..0000000000000
--- a/x-pack/plugins/triggers_actions_ui/public/application/lib/use_x_json_mode.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { useState } from 'react';
-import { XJsonMode } from '../../../../../../src/plugins/es_ui_shared/console_lang/ace/modes/x_json';
-import {
-  collapseLiteralStrings,
-  expandLiteralStrings,
-} from '../../../../../../src/plugins/es_ui_shared/console_lang/lib';
-// @ts-ignore
-export const xJsonMode = new XJsonMode();
-export const useXJsonMode = (json: Record<string, any> | null) => {
-  const [xJson, setXJson] = useState(
-    json === null ? '' : expandLiteralStrings(JSON.stringify(json, null, 2))
-  );
-
-  return {
-    xJson,
-    setXJson,
-    xJsonMode,
-    convertToJson: collapseLiteralStrings,
-  };
-};
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts
index 47de4548898cf..a35dd1346dc90 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts
@@ -4,8 +4,6 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import '../../../es_ui_shared/console_lang/mocks';
-
 import { act } from 'react-dom/test-utils';
 import { setupEnvironment, pageHelpers, nextTick, wrapBodyResponse } from './helpers';
 import { WatchCreateJsonTestBed } from './helpers/watch_create_json.helpers';
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx
index e5bdcbbfb82cf..89cd5207fe250 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx
@@ -4,8 +4,6 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import '../../../es_ui_shared/console_lang/mocks';
-
 import React from 'react';
 import { act } from 'react-dom/test-utils';
 import axiosXhrAdapter from 'axios/lib/adapters/xhr';
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts
index ced06562b1d20..18acf7339580c 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts
@@ -3,7 +3,6 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import '../../../es_ui_shared/console_lang/mocks';
 
 import { act } from 'react-dom/test-utils';
 import axiosXhrAdapter from 'axios/lib/adapters/xhr';
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts
index 3370e42b2417f..a0327c6dfa1db 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts
@@ -3,7 +3,6 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import '../../../es_ui_shared/console_lang/mocks';
 
 import { act } from 'react-dom/test-utils';
 import * as fixtures from '../../test/fixtures';
diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts
index 20b7b526705c0..e9cbb2c92491a 100644
--- a/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts
+++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts
@@ -3,7 +3,6 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import '../../../es_ui_shared/console_lang/mocks';
 
 import { act } from 'react-dom/test-utils';
 import { setupEnvironment, pageHelpers, nextTick } from './helpers';
diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx
index b3a09d3bc0e65..b5835d862000f 100644
--- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx
+++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx
@@ -23,14 +23,13 @@ import { FormattedMessage } from '@kbn/i18n/react';
 
 import { serializeJsonWatch } from '../../../../../../common/lib/serialization';
 import { ErrableFormRow, SectionError, Error as ServerError } from '../../../../components';
+import { useXJsonMode } from '../../../../shared_imports';
 import { onWatchSave } from '../../watch_edit_actions';
 import { WatchContext } from '../../watch_context';
 import { goToWatchList } from '../../../../lib/navigation';
 import { RequestFlyout } from '../request_flyout';
 import { useAppContext } from '../../../../app_context';
 
-import { useXJsonMode } from './use_x_json_mode';
-
 export const JsonWatchEditForm = () => {
   const {
     links: { putWatchApiUrl },
diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx
index b9fce52b480ef..fa0b9b0a2566f 100644
--- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx
+++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx
@@ -40,7 +40,7 @@ import { JsonWatchEditSimulateResults } from './json_watch_edit_simulate_results
 import { getTimeUnitLabel } from '../../../../lib/get_time_unit_label';
 import { useAppContext } from '../../../../app_context';
 
-import { useXJsonMode } from './use_x_json_mode';
+import { useXJsonMode } from '../../../../shared_imports';
 
 const actionModeOptions = Object.keys(ACTION_MODES).map(mode => ({
   text: ACTION_MODES[mode],
diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts
deleted file mode 100644
index 7aefb0554e0e8..0000000000000
--- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { useState } from 'react';
-import { XJsonMode } from '../../../../../../../es_ui_shared/console_lang';
-import {
-  collapseLiteralStrings,
-  expandLiteralStrings,
-} from '../../../../../../../../../src/plugins/es_ui_shared/console_lang/lib';
-
-export const xJsonMode = new XJsonMode();
-
-export const useXJsonMode = (json: string) => {
-  const [xJson, setXJson] = useState(expandLiteralStrings(json));
-
-  return {
-    xJson,
-    setXJson,
-    xJsonMode,
-    convertToJson: collapseLiteralStrings,
-  };
-};
diff --git a/x-pack/plugins/watcher/public/application/shared_imports.ts b/x-pack/plugins/watcher/public/application/shared_imports.ts
index cbc4dde7448ff..94ef7af1c28d1 100644
--- a/x-pack/plugins/watcher/public/application/shared_imports.ts
+++ b/x-pack/plugins/watcher/public/application/shared_imports.ts
@@ -11,3 +11,5 @@ export {
   sendRequest,
   useRequest,
 } from '../../../../../src/plugins/es_ui_shared/public/request/np_ready_request';
+
+export { useXJsonMode } from '../../../../../src/plugins/es_ui_shared/static/ace_x_json/hooks';

From 77d22f55d9d952ed0d3b6ed6da25def23fcea4f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cau=C3=AA=20Marcondes?=
 <55978943+cauemarcondes@users.noreply.github.com>
Date: Fri, 10 Apr 2020 13:54:48 +0100
Subject: [PATCH 49/78] [APM] Agent config select box doesn't work on IE
 (#63236)

* adding value property to select options

* fixing test
---
 .../SettingsPage/SettingFormRow.tsx                       | 7 +++++--
 .../setting_definitions/__snapshots__/index.test.ts.snap  | 4 ++++
 .../setting_definitions/general_settings.ts               | 8 ++++----
 .../agent_configuration/setting_definitions/types.d.ts    | 2 +-
 4 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx
index 30c772bf5f634..baab600145b81 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx
@@ -73,7 +73,10 @@ function FormRow({
       return (
         <SelectWithPlaceholder
           placeholder={setting.placeholder}
-          options={[{ text: 'true' }, { text: 'false' }]}
+          options={[
+            { text: 'true', value: 'true' },
+            { text: 'false', value: 'false' }
+          ]}
           value={value}
           onChange={e => onChange(setting.key, e.target.value)}
         />
@@ -105,7 +108,7 @@ function FormRow({
                 defaultMessage: 'Select unit'
               })}
               value={unit}
-              options={setting.units?.map(text => ({ text }))}
+              options={setting.units?.map(text => ({ text, value: text }))}
               onChange={e =>
                 onChange(
                   setting.key,
diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap
index 49840d2157af7..ea706be9f584a 100644
--- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap
+++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap
@@ -29,15 +29,19 @@ Array [
     "options": Array [
       Object {
         "text": "off",
+        "value": "off",
       },
       Object {
         "text": "errors",
+        "value": "errors",
       },
       Object {
         "text": "transactions",
+        "value": "transactions",
       },
       Object {
         "text": "all",
+        "value": "all",
       },
     ],
     "type": "select",
diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts
index e73aed35e87f9..7477238ba79ae 100644
--- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts
+++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts
@@ -67,10 +67,10 @@ export const generalSettings: RawSettingDefinition[] = [
       }
     ),
     options: [
-      { text: 'off' },
-      { text: 'errors' },
-      { text: 'transactions' },
-      { text: 'all' }
+      { text: 'off', value: 'off' },
+      { text: 'errors', value: 'errors' },
+      { text: 'transactions', value: 'transactions' },
+      { text: 'all', value: 'all' }
     ],
     excludeAgents: ['js-base', 'rum-js']
   },
diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts
index 282ced346dda0..815b8cb3d4e83 100644
--- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts
+++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts
@@ -76,7 +76,7 @@ interface FloatSetting extends BaseSetting {
 
 interface SelectSetting extends BaseSetting {
   type: 'select';
-  options: Array<{ text: string }>;
+  options: Array<{ text: string; value: string }>;
 }
 
 interface BooleanSetting extends BaseSetting {

From e8491adbab145590e877e5af9b1efa009400bf46 Mon Sep 17 00:00:00 2001
From: Nathan L Smith <nathan.smith@elastic.co>
Date: Fri, 10 Apr 2020 09:04:17 -0500
Subject: [PATCH 50/78] Use globe icon for "ext" span type on service map
 (#63205)

Both "external" and "ext" can be returned and should have the same icon.
---
 .../apm/public/components/app/ServiceMap/Cytoscape.stories.tsx   | 1 +
 .../legacy/plugins/apm/public/components/app/ServiceMap/icons.ts | 1 +
 2 files changed, 2 insertions(+)

diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx
index a8d3b843a1f3d..31c227d8bbcab 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx
@@ -85,6 +85,7 @@ storiesOf('app/ServiceMap/Cytoscape', module)
           }
         },
         { data: { id: 'external', 'span.type': 'external' } },
+        { data: { id: 'ext', 'span.type': 'ext' } },
         { data: { id: 'messaging', 'span.type': 'messaging' } },
         {
           data: {
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts
index dd9b48d312725..095c2d9250e27 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts
@@ -32,6 +32,7 @@ export const defaultIcon = defaultIconImport;
 const icons: { [key: string]: string } = {
   cache: databaseIcon,
   db: databaseIcon,
+  ext: globeIcon,
   external: globeIcon,
   messaging: documentsIcon,
   resource: globeIcon

From ed975d0169e6728db9d8c5cf98ca655293217192 Mon Sep 17 00:00:00 2001
From: DianaDerevyankina <54894989+DianaDerevyankina@users.noreply.github.com>
Date: Fri, 10 Apr 2020 17:59:50 +0300
Subject: [PATCH 51/78] Move shared vislib components into Charts plugin
 (#62957)

* Closes #56310

Move shared vislib components into Charts plugin

* Fixed imports in tests

* Changed i18n IDs to match charts namespace

* Renamed ColorSchemaVislibParams to ColorSchemaParams, added enums and got rid of useValidation function

* Renamed ColorSchemaVislibParams to ColorSchemaParams and got rid of useValidation function

* Fixed merge conflict

* Replaced enums with objects again
---
 .../public/components/region_map_options.tsx  |  6 ++-
 .../public/components/tile_map_options.tsx    |  2 +-
 .../components/wms_internal_options.tsx       |  2 +-
 .../public/components/wms_options.tsx         |  2 +-
 .../public/settings_options.tsx               |  2 +-
 .../public/components/metric_vis_options.tsx  |  4 +-
 .../vis_type_metric/public/metric_vis_fn.ts   |  3 +-
 .../vis_type_metric/public/metric_vis_type.ts |  3 +-
 .../vis_type_metric/public/types.ts           |  3 +-
 .../public/components/table_vis_options.tsx   |  6 ++-
 .../public/components/tag_cloud_options.tsx   |  2 +-
 .../vis_type_vislib/public/area.ts            |  2 +-
 .../public/components/common/index.ts         |  8 ----
 .../components/options/gauge/labels_panel.tsx |  2 +-
 .../components/options/gauge/ranges_panel.tsx | 14 +++---
 .../components/options/gauge/style_panel.tsx  |  2 +-
 .../components/options/heatmap/index.tsx      |  6 +--
 .../options/heatmap/labels_panel.tsx          |  2 +-
 .../metrics_axes/category_axis_panel.tsx      |  2 +-
 .../options/metrics_axes/chart_options.tsx    |  2 +-
 .../metrics_axes/custom_extents_options.tsx   |  2 +-
 .../options/metrics_axes/label_options.tsx    |  3 +-
 .../metrics_axes/line_options.test.tsx        |  2 +-
 .../options/metrics_axes/line_options.tsx     |  6 ++-
 .../components/options/metrics_axes/mocks.ts  |  3 +-
 .../metrics_axes/value_axis_options.test.tsx  |  2 +-
 .../metrics_axes/value_axis_options.tsx       |  6 ++-
 .../options/metrics_axes/y_extents.test.tsx   |  2 +-
 .../options/metrics_axes/y_extents.tsx        |  2 +-
 .../public/components/options/pie.tsx         |  3 +-
 .../options/point_series/grid_panel.tsx       |  2 +-
 .../options/point_series/point_series.tsx     |  3 +-
 .../options/point_series/threshold_panel.tsx  | 12 ++++--
 .../vis_type_vislib/public/gauge.ts           | 13 ++++--
 .../vis_type_vislib/public/goal.ts            |  4 +-
 .../vis_type_vislib/public/heatmap.ts         |  6 +--
 .../vis_type_vislib/public/histogram.ts       |  2 +-
 .../vis_type_vislib/public/horizontal_bar.ts  |  2 +-
 .../vis_type_vislib/public/index.ts           | 14 ------
 .../vis_type_vislib/public/line.ts            |  2 +-
 .../vis_type_vislib/public/types.ts           | 25 +----------
 .../public/utils/collections.ts               | 16 +------
 .../static/components}/basic_options.tsx      |  4 +-
 .../public/static/components/collections.ts}  | 26 +++++------
 .../static/components}/color_ranges.tsx       |  7 +--
 .../static/components}/color_schema.tsx       | 18 ++++----
 .../charts/public/static/components/index.ts  | 30 +++++++++++++
 .../static/components}/number_input.tsx       |  0
 .../public/static/components}/range.tsx       |  2 +-
 .../components}/required_number_input.tsx     | 14 +++---
 .../public/static/components}/select.tsx      |  0
 .../public/static/components}/switch.tsx      |  0
 .../public/static/components}/text_input.tsx  |  0
 .../charts/public/static/components/types.ts  | 43 +++++++++++++++++++
 src/plugins/charts/public/static/index.ts     |  1 +
 .../translations/translations/ja-JP.json      | 16 +++----
 .../translations/translations/zh-CN.json      | 16 +++----
 57 files changed, 215 insertions(+), 169 deletions(-)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/basic_options.tsx (90%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common/utils.ts => plugins/charts/public/static/components/collections.ts} (67%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/color_ranges.tsx (93%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/color_schema.tsx (82%)
 create mode 100644 src/plugins/charts/public/static/components/index.ts
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/number_input.tsx (100%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/range.tsx (96%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/required_number_input.tsx (87%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/select.tsx (100%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/switch.tsx (100%)
 rename src/{legacy/core_plugins/vis_type_vislib/public/components/common => plugins/charts/public/static/components}/text_input.tsx (100%)
 create mode 100644 src/plugins/charts/public/static/components/types.ts

diff --git a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx
index 61cfbf00ded9e..187b27953830d 100644
--- a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx
+++ b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx
@@ -24,7 +24,11 @@ import { FormattedMessage } from '@kbn/i18n/react';
 
 import { FileLayerField, VectorLayer, ServiceSettings } from 'ui/vis/map/service_settings';
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
-import { NumberInputOption, SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
+import {
+  NumberInputOption,
+  SelectOption,
+  SwitchOption,
+} from '../../../../../plugins/charts/public';
 import { WmsOptions } from '../../../tile_map/public/components/wms_options';
 import { RegionMapVisParams } from '../types';
 
diff --git a/src/legacy/core_plugins/tile_map/public/components/tile_map_options.tsx b/src/legacy/core_plugins/tile_map/public/components/tile_map_options.tsx
index 9169647aa2aef..9ca42fe3e4074 100644
--- a/src/legacy/core_plugins/tile_map/public/components/tile_map_options.tsx
+++ b/src/legacy/core_plugins/tile_map/public/components/tile_map_options.tsx
@@ -27,7 +27,7 @@ import {
   RangeOption,
   SelectOption,
   SwitchOption,
-} from '../../../vis_type_vislib/public';
+} from '../../../../../plugins/charts/public';
 import { WmsOptions } from './wms_options';
 import { TileMapVisParams } from '../types';
 import { MapTypes } from '../map_types';
diff --git a/src/legacy/core_plugins/tile_map/public/components/wms_internal_options.tsx b/src/legacy/core_plugins/tile_map/public/components/wms_internal_options.tsx
index b81667400303d..47f5b8f31e62b 100644
--- a/src/legacy/core_plugins/tile_map/public/components/wms_internal_options.tsx
+++ b/src/legacy/core_plugins/tile_map/public/components/wms_internal_options.tsx
@@ -21,7 +21,7 @@ import React from 'react';
 import { EuiLink, EuiSpacer, EuiText, EuiScreenReaderOnly } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-import { TextInputOption } from '../../../vis_type_vislib/public';
+import { TextInputOption } from '../../../../../plugins/charts/public';
 import { WMSOptions } from '../types';
 
 interface WmsInternalOptions {
diff --git a/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx b/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx
index 27127b781cd4d..b8535e72e8818 100644
--- a/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx
+++ b/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx
@@ -25,7 +25,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
 import { TmsLayer } from 'ui/vis/map/service_settings';
 import { Vis } from '../../../../../plugins/visualizations/public';
 import { RegionMapVisParams } from '../../../region_map/public/types';
-import { SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
+import { SelectOption, SwitchOption } from '../../../../../plugins/charts/public';
 import { WmsInternalOptions } from './wms_internal_options';
 import { WMSOptions, TileMapVisParams } from '../types';
 
diff --git a/src/legacy/core_plugins/vis_type_markdown/public/settings_options.tsx b/src/legacy/core_plugins/vis_type_markdown/public/settings_options.tsx
index 552fd63373554..16b2749c34e10 100644
--- a/src/legacy/core_plugins/vis_type_markdown/public/settings_options.tsx
+++ b/src/legacy/core_plugins/vis_type_markdown/public/settings_options.tsx
@@ -22,7 +22,7 @@ import { EuiPanel } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
-import { RangeOption, SwitchOption } from '../../vis_type_vislib/public';
+import { RangeOption, SwitchOption } from '../../../../plugins/charts/public';
 import { MarkdownVisParams } from './types';
 
 function SettingsOptions({ stateParams, setValue }: VisOptionsProps<MarkdownVisParams>) {
diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx
index 5c3032511f09a..56af0ee91878f 100644
--- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx
+++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx
@@ -37,9 +37,9 @@ import {
   SwitchOption,
   RangeOption,
   SetColorSchemaOptionsValue,
-} from '../../../vis_type_vislib/public';
+  SetColorRangeValue,
+} from '../../../../../plugins/charts/public';
 import { MetricVisParam, VisParams } from '../types';
-import { SetColorRangeValue } from '../../../vis_type_vislib/public/components/common/color_ranges';
 
 function MetricVisOptions({
   stateParams,
diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts
index 03b412c6fff15..52784da1bd73b 100644
--- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts
+++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts
@@ -26,9 +26,8 @@ import {
   Render,
   Style,
 } from '../../../../plugins/expressions/public';
-import { ColorModes } from '../../vis_type_vislib/public';
 import { visType, DimensionsVisParam, VisParams } from './types';
-import { ColorSchemas, vislibColorMaps } from '../../../../plugins/charts/public';
+import { ColorSchemas, vislibColorMaps, ColorModes } from '../../../../plugins/charts/public';
 
 export type Input = KibanaDatatable;
 
diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts
index 3bbb8964122e5..ab31c56921412 100644
--- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts
+++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts
@@ -21,8 +21,7 @@ import { i18n } from '@kbn/i18n';
 
 import { MetricVisComponent } from './components/metric_vis_component';
 import { MetricVisOptions } from './components/metric_vis_options';
-import { ColorModes } from '../../vis_type_vislib/public';
-import { ColorSchemas, colorSchemas } from '../../../../plugins/charts/public';
+import { ColorSchemas, colorSchemas, ColorModes } from '../../../../plugins/charts/public';
 import { AggGroupNames } from '../../../../plugins/data/public';
 import { Schemas } from '../../../../plugins/vis_default_editor/public';
 
diff --git a/src/legacy/core_plugins/vis_type_metric/public/types.ts b/src/legacy/core_plugins/vis_type_metric/public/types.ts
index cae18dd8a2ab1..cdf62cba934d7 100644
--- a/src/legacy/core_plugins/vis_type_metric/public/types.ts
+++ b/src/legacy/core_plugins/vis_type_metric/public/types.ts
@@ -19,8 +19,7 @@
 
 import { Range } from '../../../../plugins/expressions/public';
 import { SchemaConfig } from '../../../../plugins/visualizations/public';
-import { ColorModes, Labels, Style } from '../../vis_type_vislib/public';
-import { ColorSchemas } from '../../../../plugins/charts/public';
+import { ColorModes, ColorSchemas, Labels, Style } from '../../../../plugins/charts/public';
 
 export const visType = 'metric';
 
diff --git a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx
index d01ab31e0a843..265528f33f9cd 100644
--- a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx
+++ b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx
@@ -25,7 +25,11 @@ import { FormattedMessage } from '@kbn/i18n/react';
 
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
 import { search } from '../../../../../plugins/data/public';
-import { NumberInputOption, SwitchOption, SelectOption } from '../../../vis_type_vislib/public';
+import {
+  SwitchOption,
+  SelectOption,
+  NumberInputOption,
+} from '../../../../../plugins/charts/public';
 import { TableVisParams } from '../types';
 import { totalAggregations } from './utils';
 
diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx
index 80e4e1de7ddab..7a64549edd747 100644
--- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx
+++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx
@@ -22,7 +22,7 @@ import { EuiPanel } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
 import { ValidatedDualRange } from '../../../../../../src/plugins/kibana_react/public';
-import { SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
+import { SelectOption, SwitchOption } from '../../../../../plugins/charts/public';
 import { TagCloudVisParams } from '../types';
 
 function TagCloudOptions({ stateParams, setValue, vis }: VisOptionsProps<TagCloudVisParams>) {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/area.ts b/src/legacy/core_plugins/vis_type_vislib/public/area.ts
index 68decacaaa040..8a196da64fc4b 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/area.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/area.ts
@@ -33,13 +33,13 @@ import {
   AxisTypes,
   ScaleTypes,
   AxisModes,
-  Rotates,
   ThresholdLineStyles,
   getConfigCollections,
 } from './utils/collections';
 import { getAreaOptionTabs, countLabel } from './utils/common_config';
 import { createVislibVisController } from './vis_controller';
 import { VisTypeVislibDependencies } from './plugin';
+import { Rotates } from '../../../../plugins/charts/public';
 
 export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
   name: 'area',
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/index.ts b/src/legacy/core_plugins/vis_type_vislib/public/components/common/index.ts
index 05972d101f576..f0bec3167cb7c 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/index.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/common/index.ts
@@ -17,13 +17,5 @@
  * under the License.
  */
 
-export { BasicOptions } from './basic_options';
-export { ColorRanges } from './color_ranges';
-export { ColorSchemaOptions, SetColorSchemaOptionsValue } from './color_schema';
-export { NumberInputOption } from './number_input';
-export { RangeOption } from './range';
-export { SelectOption } from './select';
-export { SwitchOption } from './switch';
-export { TextInputOption } from './text_input';
 export { TruncateLabelsOption } from './truncate_labels';
 export { ValidationWrapper, ValidationVisOptionsProps } from './validation_wrapper';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx
index b9bae1cad35e7..3fca9dc8adc08 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx
@@ -22,7 +22,7 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-import { SwitchOption, TextInputOption } from '../../common';
+import { SwitchOption, TextInputOption } from '../../../../../../../plugins/charts/public';
 import { GaugeOptionsInternalProps } from '.';
 
 function LabelsPanel({ stateParams, setValue, setGaugeValue }: GaugeOptionsInternalProps) {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx
index 7de64e5888096..433cc4edeb47b 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx
@@ -22,12 +22,16 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-import { ColorRanges, ColorSchemaOptions, SwitchOption } from '../../common';
+import {
+  ColorRanges,
+  ColorSchemaOptions,
+  ColorSchemaParams,
+  SetColorRangeValue,
+  SwitchOption,
+  ColorSchemas,
+} from '../../../../../../../plugins/charts/public';
 import { GaugeOptionsInternalProps } from '.';
-import { ColorSchemaVislibParams } from '../../../types';
 import { Gauge } from '../../../gauge';
-import { SetColorRangeValue } from '../../common/color_ranges';
-import { ColorSchemas } from '../../../../../../../plugins/charts/public';
 
 function RangesPanel({
   setGaugeValue,
@@ -39,7 +43,7 @@ function RangesPanel({
   vis,
 }: GaugeOptionsInternalProps) {
   const setColorSchemaOptions = useCallback(
-    <T extends keyof ColorSchemaVislibParams>(paramName: T, value: ColorSchemaVislibParams[T]) => {
+    <T extends keyof ColorSchemaParams>(paramName: T, value: ColorSchemaParams[T]) => {
       setGaugeValue(paramName, value as Gauge[T]);
       // set outline if color schema is changed to greys
       // if outline wasn't set explicitly yet
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx
index 9254c3c18347c..48711de7d171a 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx
@@ -22,7 +22,7 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-import { SelectOption } from '../../common';
+import { SelectOption } from '../../../../../../../plugins/charts/public';
 import { GaugeOptionsInternalProps } from '.';
 import { AggGroupNames } from '../../../../../../../plugins/data/public';
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx
index 715b5902b69da..dc207ad89286f 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx
@@ -31,12 +31,12 @@ import {
   NumberInputOption,
   SelectOption,
   SwitchOption,
-} from '../../common';
-import { SetColorSchemaOptionsValue } from '../../common/color_schema';
+  SetColorSchemaOptionsValue,
+  SetColorRangeValue,
+} from '../../../../../../../plugins/charts/public';
 import { HeatmapVisParams } from '../../../heatmap';
 import { ValueAxis } from '../../../types';
 import { LabelsPanel } from './labels_panel';
-import { SetColorRangeValue } from '../../common/color_ranges';
 
 function HeatmapOptions(props: VisOptionsProps<HeatmapVisParams>) {
   const { stateParams, vis, uiState, setValue, setValidity, setTouched } = props;
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx
index 38811bd836459..3d1629740df2c 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx
@@ -26,7 +26,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
 import { ValueAxis } from '../../../types';
 import { HeatmapVisParams } from '../../../heatmap';
-import { SwitchOption } from '../../common';
+import { SwitchOption } from '../../../../../../../plugins/charts/public';
 
 const VERTICAL_ROTATION = 270;
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx
index 915885388640c..246c20a14807c 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx
@@ -25,7 +25,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
 
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
 import { Axis } from '../../../types';
-import { SelectOption, SwitchOption } from '../../common';
+import { SelectOption, SwitchOption } from '../../../../../../../plugins/charts/public';
 import { LabelOptions, SetAxisLabel } from './label_options';
 import { Positions } from '../../../utils/collections';
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx
index ec7a325ba43d1..89aab3a19c589 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx
@@ -25,7 +25,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
 import { Vis } from '../../../../../../../plugins/visualizations/public';
 import { SeriesParam, ValueAxis } from '../../../types';
 import { ChartTypes } from '../../../utils/collections';
-import { SelectOption } from '../../common';
+import { SelectOption } from '../../../../../../../plugins/charts/public';
 import { LineOptions } from './line_options';
 import { SetParamByIndex, ChangeValueAxis } from './';
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx
index 53b2ffa55a941..a3a97df9e35ae 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx
@@ -21,7 +21,7 @@ import React, { useCallback, useEffect } from 'react';
 import { i18n } from '@kbn/i18n';
 
 import { ValueAxis } from '../../../types';
-import { NumberInputOption, SwitchOption } from '../../common';
+import { NumberInputOption, SwitchOption } from '../../../../../../../plugins/charts/public';
 import { YExtents } from './y_extents';
 import { SetScale } from './value_axis_options';
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/label_options.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/label_options.tsx
index b6b54193e9f4a..bc687e56646f6 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/label_options.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/label_options.tsx
@@ -24,8 +24,9 @@ import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
 import { Axis } from '../../../types';
-import { SelectOption, SwitchOption, TruncateLabelsOption } from '../../common';
+import { TruncateLabelsOption } from '../../common';
 import { getRotateOptions } from '../../../utils/collections';
+import { SelectOption, SwitchOption } from '../../../../../../../plugins/charts/public';
 
 export type SetAxisLabel = <T extends keyof Axis['labels']>(
   paramName: T,
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.test.tsx
index 1d29d39bfcb7f..5354bc9c033e6 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.test.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.test.tsx
@@ -20,7 +20,7 @@
 import React from 'react';
 import { shallow } from 'enzyme';
 import { LineOptions, LineOptionsParams } from './line_options';
-import { NumberInputOption } from '../../common';
+import { NumberInputOption } from '../../../../../../../plugins/charts/public';
 import { seriesParam, vis } from './mocks';
 
 jest.mock('ui/new_platform');
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.tsx
index 01a69a6fac70b..76f95bd93caf8 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/line_options.tsx
@@ -24,7 +24,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
 
 import { Vis } from '../../../../../../../plugins/visualizations/public';
 import { SeriesParam } from '../../../types';
-import { NumberInputOption, SelectOption, SwitchOption } from '../../common';
+import {
+  NumberInputOption,
+  SelectOption,
+  SwitchOption,
+} from '../../../../../../../plugins/charts/public';
 import { SetChart } from './chart_options';
 
 export interface LineOptionsParams {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/mocks.ts b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/mocks.ts
index 0d9fa8c25a4f7..a296281375dac 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/mocks.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/mocks.ts
@@ -18,7 +18,7 @@
  */
 
 import { Vis } from '../../../../../../../plugins/visualizations/public';
-import { Axis, ValueAxis, SeriesParam, Style } from '../../../types';
+import { Axis, ValueAxis, SeriesParam } from '../../../types';
 import {
   ChartTypes,
   ChartModes,
@@ -31,6 +31,7 @@ import {
   getPositions,
   getInterpolationModes,
 } from '../../../utils/collections';
+import { Style } from '../../../../../../../plugins/charts/public';
 
 const defaultValueAxisId = 'ValueAxis-1';
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx
index 955867e66d09f..876a6917ee0b4 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx
@@ -21,7 +21,7 @@ import React from 'react';
 import { shallow } from 'enzyme';
 import { ValueAxisOptions, ValueAxisOptionsParams } from './value_axis_options';
 import { ValueAxis } from '../../../types';
-import { TextInputOption } from '../../common';
+import { TextInputOption } from '../../../../../../../plugins/charts/public';
 import { LabelOptions } from './label_options';
 import { ScaleTypes, Positions } from '../../../utils/collections';
 import { valueAxis, vis } from './mocks';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx
index 8f0327e78c7ab..1b89a766d0591 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx
@@ -24,7 +24,11 @@ import { EuiSpacer, EuiAccordion, EuiHorizontalRule } from '@elastic/eui';
 import { Vis } from '../../../../../../../plugins/visualizations/public';
 import { ValueAxis } from '../../../types';
 import { Positions } from '../../../utils/collections';
-import { SelectOption, SwitchOption, TextInputOption } from '../../common';
+import {
+  SelectOption,
+  SwitchOption,
+  TextInputOption,
+} from '../../../../../../../plugins/charts/public';
 import { LabelOptions, SetAxisLabel } from './label_options';
 import { CustomExtentsOptions } from './custom_extents_options';
 import { isAxisHorizontal } from './utils';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx
index 17c47b35b20dc..b5ed475ca8e31 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx
@@ -21,7 +21,7 @@ import React from 'react';
 import { mount, shallow } from 'enzyme';
 import { YExtents, YExtentsProps } from './y_extents';
 import { ScaleTypes } from '../../../utils/collections';
-import { NumberInputOption } from '../../common';
+import { NumberInputOption } from '../../../../../../../plugins/charts/public';
 
 jest.mock('ui/new_platform');
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx
index c0db58a612e71..faeb6069b5126 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx
@@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
 
 import { Scale } from '../../../types';
 import { ScaleTypes } from '../../../utils/collections';
-import { NumberInputOption } from '../../common';
+import { NumberInputOption } from '../../../../../../../plugins/charts/public';
 import { SetScale } from './value_axis_options';
 
 const rangeError = i18n.translate('visTypeVislib.controls.pointSeries.valueAxes.minErrorMessage', {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/pie.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/pie.tsx
index 4c0be456aad64..f6be9cd0bd8fe 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/pie.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/pie.tsx
@@ -23,7 +23,8 @@ import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
-import { BasicOptions, TruncateLabelsOption, SwitchOption } from '../common';
+import { TruncateLabelsOption } from '../common';
+import { BasicOptions, SwitchOption } from '../../../../../../plugins/charts/public';
 import { PieVisParams } from '../../pie';
 
 function PieOptions(props: VisOptionsProps<PieVisParams>) {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx
index bb2b3f8fddb49..392d180d2c5f2 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx
@@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
-import { SelectOption, SwitchOption } from '../../common';
+import { SelectOption, SwitchOption } from '../../../../../../../plugins/charts/public';
 import { BasicVislibParams, ValueAxis } from '../../../types';
 
 function GridPanel({ stateParams, setValue, hasHistogramAgg }: VisOptionsProps<BasicVislibParams>) {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx
index b9872ab94bd0b..903c1917751d9 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx
@@ -21,7 +21,8 @@ import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-import { BasicOptions, SwitchOption, ValidationVisOptionsProps } from '../../common';
+import { ValidationVisOptionsProps } from '../../common';
+import { BasicOptions, SwitchOption } from '../../../../../../../plugins/charts/public';
 import { GridPanel } from './grid_panel';
 import { ThresholdPanel } from './threshold_panel';
 import { BasicVislibParams } from '../../../types';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx
index 7866ad74ede7f..12f058ec7dd1f 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx
+++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx
@@ -21,8 +21,12 @@ import { EuiPanel, EuiTitle, EuiColorPicker, EuiFormRow, EuiSpacer } from '@elas
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-import { SelectOption, SwitchOption, ValidationVisOptionsProps } from '../../common';
-import { NumberInputOption } from '../../common/required_number_input';
+import { ValidationVisOptionsProps } from '../../common';
+import {
+  SelectOption,
+  SwitchOption,
+  RequiredNumberInputOption,
+} from '../../../../../../../plugins/charts/public';
 import { BasicVislibParams } from '../../../types';
 
 function ThresholdPanel({
@@ -73,7 +77,7 @@ function ThresholdPanel({
 
       {stateParams.thresholdLine.show && (
         <>
-          <NumberInputOption
+          <RequiredNumberInputOption
             label={i18n.translate('visTypeVislib.editors.pointSeries.thresholdLine.valueLabel', {
               defaultMessage: 'Threshold value',
             })}
@@ -83,7 +87,7 @@ function ThresholdPanel({
             setValidity={setThresholdLineValidity}
           />
 
-          <NumberInputOption
+          <RequiredNumberInputOption
             label={i18n.translate('visTypeVislib.editors.pointSeries.thresholdLine.widthLabel', {
               defaultMessage: 'Line width',
             })}
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/gauge.ts b/src/legacy/core_plugins/vis_type_vislib/public/gauge.ts
index 7ad821dbf2f30..5e0b2b8fbd36c 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/gauge.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/gauge.ts
@@ -22,13 +22,18 @@ import { i18n } from '@kbn/i18n';
 import { RangeValues, Schemas } from '../../../../plugins/vis_default_editor/public';
 import { AggGroupNames } from '../../../../plugins/data/public';
 import { GaugeOptions } from './components/options';
-import { getGaugeCollections, Alignments, ColorModes, GaugeTypes } from './utils/collections';
+import { getGaugeCollections, Alignments, GaugeTypes } from './utils/collections';
+import {
+  ColorModes,
+  ColorSchemas,
+  ColorSchemaParams,
+  Labels,
+  Style,
+} from '../../../../plugins/charts/public';
 import { createVislibVisController } from './vis_controller';
-import { ColorSchemaVislibParams, Labels, Style } from './types';
 import { VisTypeVislibDependencies } from './plugin';
-import { ColorSchemas } from '../../../../plugins/charts/public';
 
-export interface Gauge extends ColorSchemaVislibParams {
+export interface Gauge extends ColorSchemaParams {
   backStyle: 'Full';
   gaugeStyle: 'Full';
   orientation: 'vertical';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/goal.ts b/src/legacy/core_plugins/vis_type_vislib/public/goal.ts
index 6c311bebe0717..0f70dca69728d 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/goal.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/goal.ts
@@ -20,10 +20,10 @@
 import { i18n } from '@kbn/i18n';
 
 import { GaugeOptions } from './components/options';
-import { getGaugeCollections, GaugeTypes, ColorModes } from './utils/collections';
+import { getGaugeCollections, GaugeTypes } from './utils/collections';
 import { createVislibVisController } from './vis_controller';
 import { VisTypeVislibDependencies } from './plugin';
-import { ColorSchemas } from '../../../../plugins/charts/public';
+import { ColorModes, ColorSchemas } from '../../../../plugins/charts/public';
 import { AggGroupNames } from '../../../../plugins/data/public';
 import { Schemas } from '../../../../plugins/vis_default_editor/public';
 
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/heatmap.ts b/src/legacy/core_plugins/vis_type_vislib/public/heatmap.ts
index 88b4f0fcaf87e..9feed60b984ba 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/heatmap.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/heatmap.ts
@@ -25,11 +25,11 @@ import { AxisTypes, getHeatmapCollections, Positions, ScaleTypes } from './utils
 import { HeatmapOptions } from './components/options';
 import { createVislibVisController } from './vis_controller';
 import { TimeMarker } from './vislib/visualizations/time_marker';
-import { CommonVislibParams, ColorSchemaVislibParams, ValueAxis } from './types';
+import { CommonVislibParams, ValueAxis } from './types';
 import { VisTypeVislibDependencies } from './plugin';
-import { ColorSchemas } from '../../../../plugins/charts/public';
+import { ColorSchemas, ColorSchemaParams } from '../../../../plugins/charts/public';
 
-export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaVislibParams {
+export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams {
   type: 'heatmap';
   addLegend: boolean;
   enableHover: boolean;
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/histogram.ts b/src/legacy/core_plugins/vis_type_vislib/public/histogram.ts
index 54ec8f98203e2..54ccf66f362ca 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/histogram.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/histogram.ts
@@ -32,13 +32,13 @@ import {
   AxisTypes,
   ScaleTypes,
   AxisModes,
-  Rotates,
   ThresholdLineStyles,
   getConfigCollections,
 } from './utils/collections';
 import { getAreaOptionTabs, countLabel } from './utils/common_config';
 import { createVislibVisController } from './vis_controller';
 import { VisTypeVislibDependencies } from './plugin';
+import { Rotates } from '../../../../plugins/charts/public';
 
 export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
   name: 'histogram',
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/horizontal_bar.ts b/src/legacy/core_plugins/vis_type_vislib/public/horizontal_bar.ts
index dc47252ccd44f..6f73271726660 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/horizontal_bar.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/horizontal_bar.ts
@@ -32,13 +32,13 @@ import {
   AxisTypes,
   ScaleTypes,
   AxisModes,
-  Rotates,
   ThresholdLineStyles,
   getConfigCollections,
 } from './utils/collections';
 import { getAreaOptionTabs, countLabel } from './utils/common_config';
 import { createVislibVisController } from './vis_controller';
 import { VisTypeVislibDependencies } from './plugin';
+import { Rotates } from '../../../../plugins/charts/public';
 
 export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
   name: 'horizontal_bar',
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/index.ts b/src/legacy/core_plugins/vis_type_vislib/public/index.ts
index 1f773c4efcb02..4d7091ffb204b 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/index.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/index.ts
@@ -24,18 +24,4 @@ export function plugin(initializerContext: PluginInitializerContext) {
   return new Plugin(initializerContext);
 }
 
-export {
-  BasicOptions,
-  RangeOption,
-  ColorRanges,
-  SelectOption,
-  SetColorSchemaOptionsValue,
-  ColorSchemaOptions,
-  NumberInputOption,
-  SwitchOption,
-  TextInputOption,
-} from './components';
-
-export { ColorModes } from './utils/collections';
-
 export * from './types';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/line.ts b/src/legacy/core_plugins/vis_type_vislib/public/line.ts
index 885ab295d11e1..1f9a8d77398e6 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/line.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/line.ts
@@ -32,7 +32,6 @@ import {
   AxisTypes,
   ScaleTypes,
   AxisModes,
-  Rotates,
   ThresholdLineStyles,
   InterpolationModes,
   getConfigCollections,
@@ -40,6 +39,7 @@ import {
 import { getAreaOptionTabs, countLabel } from './utils/common_config';
 import { createVislibVisController } from './vis_controller';
 import { VisTypeVislibDependencies } from './plugin';
+import { Rotates } from '../../../../plugins/charts/public';
 
 export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
   name: 'line',
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/types.ts b/src/legacy/core_plugins/vis_type_vislib/public/types.ts
index f33b42483c53e..25c6ae5439fe8 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/types.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/types.ts
@@ -25,39 +25,16 @@ import {
   AxisModes,
   AxisTypes,
   InterpolationModes,
-  Rotates,
   ScaleTypes,
   ThresholdLineStyles,
 } from './utils/collections';
-import { ColorSchemas } from '../../../../plugins/charts/public';
+import { Labels, Style } from '../../../../plugins/charts/public';
 
 export interface CommonVislibParams {
   addTooltip: boolean;
   legendPosition: Positions;
 }
 
-export interface ColorSchemaVislibParams {
-  colorSchema: ColorSchemas;
-  invertColors: boolean;
-}
-
-export interface Labels {
-  color?: string;
-  filter?: boolean;
-  overwriteColor?: boolean;
-  rotate?: Rotates;
-  show: boolean;
-  truncate?: number | null;
-}
-
-export interface Style {
-  bgFill: string;
-  bgColor: boolean;
-  labelColor: boolean;
-  subText: string;
-  fontSize: number;
-}
-
 export interface Scale {
   boundsMargin?: number | '';
   defaultYExtents?: boolean;
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/utils/collections.ts b/src/legacy/core_plugins/vis_type_vislib/public/utils/collections.ts
index f32b765cd6e57..2024c43dd1c8b 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/utils/collections.ts
+++ b/src/legacy/core_plugins/vis_type_vislib/public/utils/collections.ts
@@ -20,7 +20,7 @@
 import { i18n } from '@kbn/i18n';
 import { $Values } from '@kbn/utility-types';
 
-import { colorSchemas } from '../../../../../plugins/charts/public';
+import { colorSchemas, Rotates } from '../../../../../plugins/charts/public';
 
 export const Positions = Object.freeze({
   RIGHT: 'right' as 'right',
@@ -203,13 +203,6 @@ const getAxisModes = () => [
   },
 ];
 
-export const Rotates = Object.freeze({
-  HORIZONTAL: 0,
-  VERTICAL: 90,
-  ANGLED: 75,
-});
-export type Rotates = $Values<typeof Rotates>;
-
 export const ThresholdLineStyles = Object.freeze({
   FULL: 'full' as 'full',
   DASHED: 'dashed' as 'dashed',
@@ -265,13 +258,6 @@ export const GaugeTypes = Object.freeze({
 });
 export type GaugeTypes = $Values<typeof GaugeTypes>;
 
-export const ColorModes = Object.freeze({
-  BACKGROUND: 'Background' as 'Background',
-  LABELS: 'Labels' as 'Labels',
-  NONE: 'None' as 'None',
-});
-export type ColorModes = $Values<typeof ColorModes>;
-
 const getGaugeTypes = () => [
   {
     text: i18n.translate('visTypeVislib.gauge.gaugeTypes.arcText', {
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/basic_options.tsx b/src/plugins/charts/public/static/components/basic_options.tsx
similarity index 90%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/basic_options.tsx
rename to src/plugins/charts/public/static/components/basic_options.tsx
index baf3e8ecd1b28..cac4c8d70d796 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/basic_options.tsx
+++ b/src/plugins/charts/public/static/components/basic_options.tsx
@@ -37,7 +37,7 @@ function BasicOptions<VisParams extends BasicOptionsParams>({
   return (
     <>
       <SelectOption
-        label={i18n.translate('visTypeVislib.controls.vislibBasicOptions.legendPositionLabel', {
+        label={i18n.translate('charts.controls.vislibBasicOptions.legendPositionLabel', {
           defaultMessage: 'Legend position',
         })}
         options={vis.type.editorConfig.collections.legendPositions}
@@ -46,7 +46,7 @@ function BasicOptions<VisParams extends BasicOptionsParams>({
         setValue={setValue}
       />
       <SwitchOption
-        label={i18n.translate('visTypeVislib.controls.vislibBasicOptions.showTooltipLabel', {
+        label={i18n.translate('charts.controls.vislibBasicOptions.showTooltipLabel', {
           defaultMessage: 'Show tooltip',
         })}
         paramName="addTooltip"
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/utils.ts b/src/plugins/charts/public/static/components/collections.ts
similarity index 67%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/utils.ts
rename to src/plugins/charts/public/static/components/collections.ts
index d51631106dda7..9dde50f2b44c9 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/utils.ts
+++ b/src/plugins/charts/public/static/components/collections.ts
@@ -17,18 +17,18 @@
  * under the License.
  */
 
-import { useEffect } from 'react';
+import { $Values } from '@kbn/utility-types';
 
-function useValidation<ParamName extends string>(
-  setValidity: (paramName: ParamName, isValid: boolean) => void,
-  paramName: ParamName,
-  isValid: boolean
-) {
-  useEffect(() => {
-    setValidity(paramName, isValid);
+export const ColorModes = Object.freeze({
+  BACKGROUND: 'Background' as 'Background',
+  LABELS: 'Labels' as 'Labels',
+  NONE: 'None' as 'None',
+});
+export type ColorModes = $Values<typeof ColorModes>;
 
-    return () => setValidity(paramName, true);
-  }, [isValid, paramName, setValidity]);
-}
-
-export { useValidation };
+export const Rotates = Object.freeze({
+  HORIZONTAL: 0,
+  VERTICAL: 90,
+  ANGLED: 75,
+});
+export type Rotates = $Values<typeof Rotates>;
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx b/src/plugins/charts/public/static/components/color_ranges.tsx
similarity index 93%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx
rename to src/plugins/charts/public/static/components/color_ranges.tsx
index 84c70f10b12da..a9b05d7d91c7c 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx
+++ b/src/plugins/charts/public/static/components/color_ranges.tsx
@@ -22,10 +22,7 @@ import { last } from 'lodash';
 
 import { i18n } from '@kbn/i18n';
 
-import {
-  RangeValues,
-  RangesParamEditor,
-} from '../../../../../../plugins/vis_default_editor/public';
+import { RangeValues, RangesParamEditor } from '../../../../vis_default_editor/public';
 
 export type SetColorRangeValue = (paramName: string, value: RangeValues[]) => void;
 
@@ -74,7 +71,7 @@ function ColorRanges({
   return (
     <RangesParamEditor
       data-test-subj={dataTestSubj}
-      error={i18n.translate('visTypeVislib.controls.colorRanges.errorText', {
+      error={i18n.translate('charts.controls.colorRanges.errorText', {
         defaultMessage: 'Each range should be greater than previous.',
       })}
       hidePlaceholders={true}
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx b/src/plugins/charts/public/static/components/color_schema.tsx
similarity index 82%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx
rename to src/plugins/charts/public/static/components/color_schema.tsx
index 35d7f7b13235e..62fe3143f0481 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx
+++ b/src/plugins/charts/public/static/components/color_schema.tsx
@@ -25,15 +25,15 @@ import { FormattedMessage } from '@kbn/i18n/react';
 import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
 import { SelectOption } from './select';
 import { SwitchOption } from './switch';
-import { ColorSchemaVislibParams } from '../../types';
-import { ColorSchema } from '../../../../../../plugins/charts/public';
+import { ColorSchemaParams } from './types';
+import { ColorSchema } from '../color_maps';
 
-export type SetColorSchemaOptionsValue = <T extends keyof ColorSchemaVislibParams>(
+export type SetColorSchemaOptionsValue = <T extends keyof ColorSchemaParams>(
   paramName: T,
-  value: ColorSchemaVislibParams[T]
+  value: ColorSchemaParams[T]
 ) => void;
 
-interface ColorSchemaOptionsProps extends ColorSchemaVislibParams {
+interface ColorSchemaOptionsProps extends ColorSchemaParams {
   disabled?: boolean;
   colorSchemas: ColorSchema[];
   uiState: VisOptionsProps['uiState'];
@@ -67,7 +67,7 @@ function ColorSchemaOptions({
         }}
       >
         <FormattedMessage
-          id="visTypeVislib.controls.colorSchema.resetColorsButtonLabel"
+          id="charts.controls.colorSchema.resetColorsButtonLabel"
           defaultMessage="Reset colors"
         />
       </EuiLink>
@@ -80,11 +80,11 @@ function ColorSchemaOptions({
         disabled={disabled}
         helpText={
           showHelpText &&
-          i18n.translate('visTypeVislib.controls.colorSchema.howToChangeColorsDescription', {
+          i18n.translate('charts.controls.colorSchema.howToChangeColorsDescription', {
             defaultMessage: 'Individual colors can be changed in the legend.',
           })
         }
-        label={i18n.translate('visTypeVislib.controls.colorSchema.colorSchemaLabel', {
+        label={i18n.translate('charts.controls.colorSchema.colorSchemaLabel', {
           defaultMessage: 'Color schema',
         })}
         labelAppend={isCustomColors && resetColorsButton}
@@ -96,7 +96,7 @@ function ColorSchemaOptions({
 
       <SwitchOption
         disabled={disabled}
-        label={i18n.translate('visTypeVislib.controls.colorSchema.reverseColorSchemaLabel', {
+        label={i18n.translate('charts.controls.colorSchema.reverseColorSchemaLabel', {
           defaultMessage: 'Reverse schema',
         })}
         paramName="invertColors"
diff --git a/src/plugins/charts/public/static/components/index.ts b/src/plugins/charts/public/static/components/index.ts
new file mode 100644
index 0000000000000..48c9e40145481
--- /dev/null
+++ b/src/plugins/charts/public/static/components/index.ts
@@ -0,0 +1,30 @@
+/*
+ * 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 { BasicOptions } from './basic_options';
+export { ColorModes, Rotates } from './collections';
+export { ColorRanges, SetColorRangeValue } from './color_ranges';
+export { ColorSchemaOptions, SetColorSchemaOptionsValue } from './color_schema';
+export { ColorSchemaParams, Labels, Style } from './types';
+export { NumberInputOption } from './number_input';
+export { RangeOption } from './range';
+export { RequiredNumberInputOption } from './required_number_input';
+export { SelectOption } from './select';
+export { SwitchOption } from './switch';
+export { TextInputOption } from './text_input';
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/number_input.tsx b/src/plugins/charts/public/static/components/number_input.tsx
similarity index 100%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/number_input.tsx
rename to src/plugins/charts/public/static/components/number_input.tsx
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/range.tsx b/src/plugins/charts/public/static/components/range.tsx
similarity index 96%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/range.tsx
rename to src/plugins/charts/public/static/components/range.tsx
index 56774f8898bb7..5c713180924df 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/range.tsx
+++ b/src/plugins/charts/public/static/components/range.tsx
@@ -49,7 +49,7 @@ function RangeOption<ParamName extends string>({
   const [stateValue, setStateValue] = useState(value);
   const [isValidState, setIsValidState] = useState(true);
 
-  const error = i18n.translate('visTypeVislib.controls.rangeErrorMessage', {
+  const error = i18n.translate('charts.controls.rangeErrorMessage', {
     defaultMessage: 'Values must be on or between {min} and {max}',
     values: { min, max },
   });
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/required_number_input.tsx b/src/plugins/charts/public/static/components/required_number_input.tsx
similarity index 87%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/required_number_input.tsx
rename to src/plugins/charts/public/static/components/required_number_input.tsx
index 7b62016c4e502..7594c775b07ad 100644
--- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/required_number_input.tsx
+++ b/src/plugins/charts/public/static/components/required_number_input.tsx
@@ -17,9 +17,8 @@
  * under the License.
  */
 
-import React, { ReactNode, useCallback, ChangeEvent } from 'react';
+import React, { ReactNode, useCallback, ChangeEvent, useEffect } from 'react';
 import { EuiFormRow, EuiFieldNumber } from '@elastic/eui';
-import { useValidation } from './utils';
 
 interface NumberInputOptionProps<ParamName extends string> {
   disabled?: boolean;
@@ -42,7 +41,7 @@ interface NumberInputOptionProps<ParamName extends string> {
  *
  * @param {number} props.value Should be numeric only
  */
-function NumberInputOption<ParamName extends string>({
+function RequiredNumberInputOption<ParamName extends string>({
   disabled,
   error,
   isInvalid,
@@ -57,7 +56,12 @@ function NumberInputOption<ParamName extends string>({
   'data-test-subj': dataTestSubj,
 }: NumberInputOptionProps<ParamName>) {
   const isValid = value !== null;
-  useValidation(setValidity, paramName, isValid);
+
+  useEffect(() => {
+    setValidity(paramName, isValid);
+
+    return () => setValidity(paramName, true);
+  }, [isValid, paramName, setValidity]);
 
   const onChange = useCallback(
     (ev: ChangeEvent<HTMLInputElement>) =>
@@ -84,4 +88,4 @@ function NumberInputOption<ParamName extends string>({
   );
 }
 
-export { NumberInputOption };
+export { RequiredNumberInputOption };
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/select.tsx b/src/plugins/charts/public/static/components/select.tsx
similarity index 100%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/select.tsx
rename to src/plugins/charts/public/static/components/select.tsx
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/switch.tsx b/src/plugins/charts/public/static/components/switch.tsx
similarity index 100%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/switch.tsx
rename to src/plugins/charts/public/static/components/switch.tsx
diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/text_input.tsx b/src/plugins/charts/public/static/components/text_input.tsx
similarity index 100%
rename from src/legacy/core_plugins/vis_type_vislib/public/components/common/text_input.tsx
rename to src/plugins/charts/public/static/components/text_input.tsx
diff --git a/src/plugins/charts/public/static/components/types.ts b/src/plugins/charts/public/static/components/types.ts
new file mode 100644
index 0000000000000..196eb60b06aec
--- /dev/null
+++ b/src/plugins/charts/public/static/components/types.ts
@@ -0,0 +1,43 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { ColorSchemas } from '../color_maps';
+import { Rotates } from './collections';
+
+export interface ColorSchemaParams {
+  colorSchema: ColorSchemas;
+  invertColors: boolean;
+}
+
+export interface Labels {
+  color?: string;
+  filter?: boolean;
+  overwriteColor?: boolean;
+  rotate?: Rotates;
+  show: boolean;
+  truncate?: number | null;
+}
+
+export interface Style {
+  bgFill: string;
+  bgColor: boolean;
+  labelColor: boolean;
+  subText: string;
+  fontSize: number;
+}
diff --git a/src/plugins/charts/public/static/index.ts b/src/plugins/charts/public/static/index.ts
index bee58e4f1e3e1..6fc097d05467f 100644
--- a/src/plugins/charts/public/static/index.ts
+++ b/src/plugins/charts/public/static/index.ts
@@ -18,3 +18,4 @@
  */
 
 export * from './color_maps';
+export * from './components';
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index c07ec68e99b4f..09903c34e2e5e 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -130,6 +130,14 @@
     "charts.colormaps.greysText": "グレー",
     "charts.colormaps.redsText": "赤",
     "charts.colormaps.yellowToRedText": "黄色から赤",
+    "charts.controls.colorRanges.errorText": "各範囲は前の範囲よりも大きくなければなりません。",
+    "charts.controls.colorSchema.colorSchemaLabel": "配色",
+    "charts.controls.colorSchema.howToChangeColorsDescription": "それぞれの色は凡例で変更できます。",
+    "charts.controls.colorSchema.resetColorsButtonLabel": "色をリセット",
+    "charts.controls.colorSchema.reverseColorSchemaLabel": "図表を反転",
+    "charts.controls.rangeErrorMessage": "値は {min} と {max} の間でなければなりません",
+    "charts.controls.vislibBasicOptions.legendPositionLabel": "凡例位置",
+    "charts.controls.vislibBasicOptions.showTooltipLabel": "ツールヒントを表示",
     "common.ui.errorAutoCreateIndex.breadcrumbs.errorText": "エラー",
     "common.ui.errorAutoCreateIndex.errorDescription": "Elasticsearch クラスターの {autoCreateIndexActionConfig} 設定が原因で、Kibana が保存されたオブジェクトを格納するインデックスを自動的に作成できないようです。Kibana は、保存されたオブジェクトインデックスが適切なマッピング/スキーマを使用し Kibana から Elasticsearch へのポーリングの回数を減らすための最適な手段であるため、この Elasticsearch の機能を使用します。",
     "common.ui.errorAutoCreateIndex.errorDisclaimer": "申し訳ございませんが、この問題が解決されるまで Kibana で何も保存することができません。",
@@ -3831,11 +3839,6 @@
     "visTypeVislib.chartTypes.areaText": "エリア",
     "visTypeVislib.chartTypes.barText": "バー",
     "visTypeVislib.chartTypes.lineText": "折れ線",
-    "visTypeVislib.controls.colorRanges.errorText": "各範囲は前の範囲よりも大きくなければなりません。",
-    "visTypeVislib.controls.colorSchema.colorSchemaLabel": "配色",
-    "visTypeVislib.controls.colorSchema.howToChangeColorsDescription": "それぞれの色は凡例で変更できます。",
-    "visTypeVislib.controls.colorSchema.resetColorsButtonLabel": "色をリセット",
-    "visTypeVislib.controls.colorSchema.reverseColorSchemaLabel": "図表を反転",
     "visTypeVislib.controls.gaugeOptions.alignmentLabel": "アラインメント",
     "visTypeVislib.controls.gaugeOptions.autoExtendRangeLabel": "範囲を自動拡張",
     "visTypeVislib.controls.gaugeOptions.displayWarningsLabel": "警告を表示",
@@ -3902,10 +3905,7 @@
     "visTypeVislib.controls.pointSeries.valueAxes.toggleCustomExtendsAriaLabel": "カスタム範囲を切り替える",
     "visTypeVislib.controls.pointSeries.valueAxes.toggleOptionsAriaLabel": "{axisName} オプションを切り替える",
     "visTypeVislib.controls.pointSeries.valueAxes.yAxisTitle": "Y 軸",
-    "visTypeVislib.controls.rangeErrorMessage": "値は {min} と {max} の間でなければなりません",
     "visTypeVislib.controls.truncateLabel": "切り捨て",
-    "visTypeVislib.controls.vislibBasicOptions.legendPositionLabel": "凡例位置",
-    "visTypeVislib.controls.vislibBasicOptions.showTooltipLabel": "ツールヒントを表示",
     "visTypeVislib.editors.heatmap.basicSettingsTitle": "基本設定",
     "visTypeVislib.editors.heatmap.heatmapSettingsTitle": "ヒートマップ設定",
     "visTypeVislib.editors.heatmap.highlightLabel": "ハイライト範囲",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index de8aaa75632ee..cc1b7d7980a0b 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -130,6 +130,14 @@
     "charts.colormaps.greysText": "灰色",
     "charts.colormaps.redsText": "红色",
     "charts.colormaps.yellowToRedText": "黄到红",
+    "charts.controls.colorRanges.errorText": "每个范围应大于前一范围。",
+    "charts.controls.colorSchema.colorSchemaLabel": "颜色模式",
+    "charts.controls.colorSchema.howToChangeColorsDescription": "可以更改图例中的各个颜色。",
+    "charts.controls.colorSchema.resetColorsButtonLabel": "重置颜色",
+    "charts.controls.colorSchema.reverseColorSchemaLabel": "反转模式",
+    "charts.controls.rangeErrorMessage": "值必须是在 {min} 到 {max} 的范围内",
+    "charts.controls.vislibBasicOptions.legendPositionLabel": "图例位置",
+    "charts.controls.vislibBasicOptions.showTooltipLabel": "显示工具提示",
     "common.ui.errorAutoCreateIndex.breadcrumbs.errorText": "错误",
     "common.ui.errorAutoCreateIndex.errorDescription": "似乎 Elasticsearch 集群的 {autoCreateIndexActionConfig} 设置使 Kibana 无法自动创建用于存储已保存对象的索引。Kibana 将使用此 Elasticsearch 功能,因为这是确保已保存对象索引使用正确映射/架构的最好方式,而且其允许 Kibana 较少地轮询 Elasticsearch。",
     "common.ui.errorAutoCreateIndex.errorDisclaimer": "但是,只有解决了此问题后,您才能在 Kibana 保存内容。",
@@ -3832,11 +3840,6 @@
     "visTypeVislib.chartTypes.areaText": "面积图",
     "visTypeVislib.chartTypes.barText": "条形图",
     "visTypeVislib.chartTypes.lineText": "折线图",
-    "visTypeVislib.controls.colorRanges.errorText": "每个范围应大于前一范围。",
-    "visTypeVislib.controls.colorSchema.colorSchemaLabel": "颜色模式",
-    "visTypeVislib.controls.colorSchema.howToChangeColorsDescription": "可以更改图例中的各个颜色。",
-    "visTypeVislib.controls.colorSchema.resetColorsButtonLabel": "重置颜色",
-    "visTypeVislib.controls.colorSchema.reverseColorSchemaLabel": "反转模式",
     "visTypeVislib.controls.gaugeOptions.alignmentLabel": "对齐方式",
     "visTypeVislib.controls.gaugeOptions.autoExtendRangeLabel": "自动扩展范围",
     "visTypeVislib.controls.gaugeOptions.displayWarningsLabel": "显示警告",
@@ -3903,10 +3906,7 @@
     "visTypeVislib.controls.pointSeries.valueAxes.toggleCustomExtendsAriaLabel": "切换定制范围",
     "visTypeVislib.controls.pointSeries.valueAxes.toggleOptionsAriaLabel": "切换 {axisName} 选项",
     "visTypeVislib.controls.pointSeries.valueAxes.yAxisTitle": "Y 轴",
-    "visTypeVislib.controls.rangeErrorMessage": "值必须是在 {min} 到 {max} 的范围内",
     "visTypeVislib.controls.truncateLabel": "截断",
-    "visTypeVislib.controls.vislibBasicOptions.legendPositionLabel": "图例位置",
-    "visTypeVislib.controls.vislibBasicOptions.showTooltipLabel": "显示工具提示",
     "visTypeVislib.editors.heatmap.basicSettingsTitle": "基本设置",
     "visTypeVislib.editors.heatmap.heatmapSettingsTitle": "热图设置",
     "visTypeVislib.editors.heatmap.highlightLabel": "高亮范围",

From 36acb373876f3c6ea5077caae81d3a1cad239dfd Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Fri, 10 Apr 2020 11:18:12 -0400
Subject: [PATCH 52/78] Make uptime alert flyout test a little more resilient
 (#62702)

---
 .../apps/uptime/alert_flyout.ts               | 40 ++++++++++---------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts
index 2a0358160da51..3e5a8c57c4c7e 100644
--- a/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts
+++ b/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts
@@ -33,7 +33,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
       // put the fetch code in a retry block with a timeout.
       let alert: any;
       await retry.tryForTime(15000, async () => {
-        const apiResponse = await supertest.get('/api/alert/_find');
+        const apiResponse = await supertest.get('/api/alert/_find?search=uptime-test');
         const alertsFromThisTest = apiResponse.body.data.filter(
           ({ name }: { name: string }) => name === 'uptime-test'
         );
@@ -54,25 +54,27 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
         tags,
       } = alert;
 
-      // we're not testing the flyout's ability to associate alerts with action connectors
-      expect(actions).to.eql([]);
+      try {
+        // we're not testing the flyout's ability to associate alerts with action connectors
+        expect(actions).to.eql([]);
 
-      expect(alertTypeId).to.eql('xpack.uptime.alerts.monitorStatus');
-      expect(consumer).to.eql('uptime');
-      expect(interval).to.eql('11m');
-      expect(tags).to.eql(['uptime', 'another']);
-      expect(numTimes).to.be(3);
-      expect(timerange.from).to.be('now-1h');
-      expect(timerange.to).to.be('now');
-      expect(locations).to.eql(['mpls']);
-      expect(filters).to.eql(
-        '{"bool":{"should":[{"match_phrase":{"monitor.id":"0001-up"}}],"minimum_should_match":1}}'
-      );
-
-      await supertest
-        .delete(`/api/alert/${id}`)
-        .set('kbn-xsrf', 'true')
-        .expect(204);
+        expect(alertTypeId).to.eql('xpack.uptime.alerts.monitorStatus');
+        expect(consumer).to.eql('uptime');
+        expect(interval).to.eql('11m');
+        expect(tags).to.eql(['uptime', 'another']);
+        expect(numTimes).to.be(3);
+        expect(timerange.from).to.be('now-1h');
+        expect(timerange.to).to.be('now');
+        expect(locations).to.eql(['mpls']);
+        expect(filters).to.eql(
+          '{"bool":{"should":[{"match_phrase":{"monitor.id":"0001-up"}}],"minimum_should_match":1}}'
+        );
+      } finally {
+        await supertest
+          .delete(`/api/alert/${id}`)
+          .set('kbn-xsrf', 'true')
+          .expect(204);
+      }
     });
   });
 };

From 55a3cc45835ccf267c06c2d0d62000027d2bf006 Mon Sep 17 00:00:00 2001
From: Steph Milovic <stephanie.milovic@elastic.co>
Date: Fri, 10 Apr 2020 09:55:38 -0600
Subject: [PATCH 53/78] [SIEM] [Cases] Unit tests for case UI components
 (#63005)

---
 .../components/filter_popover/index.tsx       |   1 +
 .../components/header_page/editable_title.tsx |   9 +-
 .../siem/public/containers/case/api.ts        |   4 +-
 .../case/configure/use_configure.tsx          |   4 +-
 .../plugins/siem/public/pages/case/case.tsx   |   9 +-
 .../siem/public/pages/case/case_details.tsx   |   6 +-
 .../case/components/__mock__/case_data.tsx    | 226 ++++++++++++
 .../pages/case/components/__mock__/form.ts    |  37 ++
 .../pages/case/components/__mock__/router.ts  |  39 +++
 .../components/add_comment/index.test.tsx     | 144 ++++++++
 .../case/components/add_comment/index.tsx     |   6 +-
 .../components/all_cases/__mock__/index.tsx   | 115 ------
 .../components/all_cases/columns.test.tsx     |  48 +++
 .../case/components/all_cases/columns.tsx     |  14 +-
 .../case/components/all_cases/index.test.tsx  |  66 +++-
 .../all_cases/table_filters.test.tsx          | 121 +++++++
 .../components/all_cases/table_filters.tsx    |   7 +-
 .../case/components/all_cases/translations.ts |   4 +
 .../pages/case/components/callout/helpers.tsx |   4 +-
 .../case/components/callout/index.test.tsx    |  71 ++++
 .../pages/case/components/callout/index.tsx   |  10 +-
 .../case/components/case_status/index.tsx     |   2 +-
 .../components/case_view/__mock__/index.tsx   |  93 -----
 .../components/case_view/actions.test.tsx     |  10 +-
 .../case/components/case_view/actions.tsx     |   1 -
 .../case/components/case_view/index.test.tsx  | 320 +++++++++++++----
 .../pages/case/components/case_view/index.tsx |   8 +-
 .../case/components/create/index.test.tsx     | 121 +++++++
 .../pages/case/components/create/index.tsx    |   7 +-
 .../case/components/tag_list/index.test.tsx   | 138 ++++++++
 .../pages/case/components/tag_list/index.tsx  |  17 +-
 .../use_push_to_service/index.test.tsx        | 192 ++++++++++
 .../components/use_push_to_service/index.tsx  |   5 +-
 .../user_action_tree/helpers.test.tsx         | 143 ++++++++
 .../components/user_action_tree/helpers.tsx   |  12 +-
 .../user_action_tree/index.test.tsx           | 331 ++++++++++++++++++
 .../components/user_action_tree/index.tsx     |  10 +-
 .../user_action_tree/user_action_item.tsx     |  15 +-
 .../user_action_tree/user_action_markdown.tsx |  20 +-
 .../user_action_title.test.tsx                |  57 +++
 .../user_action_tree/user_action_title.tsx    |  16 +-
 .../siem/public/pages/case/translations.ts    |   4 +
 .../scripts/generate_case_and_comment_data.sh |   6 +-
 .../case/server/scripts/generate_case_data.sh |   4 +-
 44 files changed, 2117 insertions(+), 360 deletions(-)
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/case_data.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/form.ts
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/router.ts
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.test.tsx
 delete mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.test.tsx
 delete mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/create/index.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx
 create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.test.tsx

diff --git a/x-pack/legacy/plugins/siem/public/components/filter_popover/index.tsx b/x-pack/legacy/plugins/siem/public/components/filter_popover/index.tsx
index 3c01ec18a879f..fca6396a53745 100644
--- a/x-pack/legacy/plugins/siem/public/components/filter_popover/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/filter_popover/index.tsx
@@ -89,6 +89,7 @@ export const FilterPopoverComponent = ({
         {options.map((option, index) => (
           <EuiFilterSelectItem
             checked={selectedOptions.includes(option) ? 'on' : undefined}
+            data-test-subj={`options-filter-popover-item-${index}`}
             key={`${index}-${option}`}
             onClick={toggleSelectedGroupCb.bind(null, option)}
           >
diff --git a/x-pack/legacy/plugins/siem/public/components/header_page/editable_title.tsx b/x-pack/legacy/plugins/siem/public/components/header_page/editable_title.tsx
index 165be00384779..0c6f7258d09dc 100644
--- a/x-pack/legacy/plugins/siem/public/components/header_page/editable_title.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/header_page/editable_title.tsx
@@ -60,12 +60,9 @@ const EditableTitleComponent: React.FC<Props> = ({
   }, [changedTitle, title]);
 
   const handleOnChange = useCallback(
-    (e: ChangeEvent<HTMLInputElement>) => {
-      onTitleChange(e.target.value);
-    },
-    [onTitleChange]
+    (e: ChangeEvent<HTMLInputElement>) => onTitleChange(e.target.value),
+    []
   );
-
   return editMode ? (
     <EuiFlexGroup alignItems="center" gutterSize="m" justifyContent="spaceBetween">
       <EuiFlexItem grow={false}>
@@ -107,7 +104,7 @@ const EditableTitleComponent: React.FC<Props> = ({
         <Title title={title} />
       </EuiFlexItem>
       <EuiFlexItem grow={false}>
-        {isLoading && <MySpinner />}
+        {isLoading && <MySpinner data-test-subj="editable-title-loading" />}
         {!isLoading && (
           <MyEuiButtonIcon
             isDisabled={disabled}
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/api.ts b/x-pack/legacy/plugins/siem/public/containers/case/api.ts
index 69e1602b3d981..12b4c80a2dd89 100644
--- a/x-pack/legacy/plugins/siem/public/containers/case/api.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/case/api.ts
@@ -204,13 +204,13 @@ export const patchComment = async (
   return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response));
 };
 
-export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<boolean> => {
+export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<string> => {
   const response = await KibanaServices.get().http.fetch<string>(CASES_URL, {
     method: 'DELETE',
     query: { ids: JSON.stringify(caseIds) },
     signal,
   });
-  return response === 'true' ? true : false;
+  return response;
 };
 
 export const pushCase = async (
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx
index 7f57149d4e56d..1c03a09a8c2ea 100644
--- a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx
@@ -55,7 +55,6 @@ export const useCaseConfigure = ({
         setLoading(true);
         const res = await getCaseConfigure({ signal: abortCtrl.signal });
         if (!didCancel) {
-          setLoading(false);
           if (res != null) {
             setConnector(res.connectorId, res.connectorName);
             if (setClosureType != null) {
@@ -73,6 +72,7 @@ export const useCaseConfigure = ({
               }
             }
           }
+          setLoading(false);
         }
       } catch (error) {
         if (!didCancel) {
@@ -117,7 +117,6 @@ export const useCaseConfigure = ({
                   abortCtrl.signal
                 );
           if (!didCancel) {
-            setPersistLoading(false);
             setConnector(res.connectorId);
             if (setClosureType) {
               setClosureType(res.closureType);
@@ -131,6 +130,7 @@ export const useCaseConfigure = ({
             }
 
             displaySuccessToast(i18n.SUCCESS_CONFIGURE, dispatchToaster);
+            setPersistLoading(false);
           }
         } catch (error) {
           if (!didCancel) {
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/case.tsx b/x-pack/legacy/plugins/siem/public/pages/case/case.tsx
index 2ae35796387b8..aefb0a93366b8 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/case.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/case.tsx
@@ -11,11 +11,9 @@ import { useGetUserSavedObjectPermissions } from '../../lib/kibana';
 import { SpyRoute } from '../../utils/route/spy_routes';
 import { AllCases } from './components/all_cases';
 
-import { getSavedObjectReadOnly, CaseCallOut } from './components/callout';
+import { savedObjectReadOnly, CaseCallOut } from './components/callout';
 import { CaseSavedObjectNoPermissions } from './saved_object_no_permissions';
 
-const infoReadSavedObject = getSavedObjectReadOnly();
-
 export const CasesPage = React.memo(() => {
   const userPermissions = useGetUserSavedObjectPermissions();
 
@@ -24,10 +22,11 @@ export const CasesPage = React.memo(() => {
       <WrapperPage>
         {userPermissions != null && !userPermissions?.crud && userPermissions?.read && (
           <CaseCallOut
-            title={infoReadSavedObject.title}
-            message={infoReadSavedObject.description}
+            title={savedObjectReadOnly.title}
+            message={savedObjectReadOnly.description}
           />
         )}
+        <CaseCallOut title={savedObjectReadOnly.title} message={savedObjectReadOnly.description} />
         <AllCases userCanCrud={userPermissions?.crud ?? false} />
       </WrapperPage>
       <SpyRoute />
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/case_details.tsx b/x-pack/legacy/plugins/siem/public/pages/case/case_details.tsx
index cbc7bbc62fbf9..4bb8afa7f8d42 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/case_details.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/case_details.tsx
@@ -13,9 +13,7 @@ import { SpyRoute } from '../../utils/route/spy_routes';
 import { getCaseUrl } from '../../components/link_to';
 import { navTabs } from '../home/home_navigations';
 import { CaseView } from './components/case_view';
-import { getSavedObjectReadOnly, CaseCallOut } from './components/callout';
-
-const infoReadSavedObject = getSavedObjectReadOnly();
+import { savedObjectReadOnly, CaseCallOut } from './components/callout';
 
 export const CaseDetailsPage = React.memo(() => {
   const userPermissions = useGetUserSavedObjectPermissions();
@@ -29,7 +27,7 @@ export const CaseDetailsPage = React.memo(() => {
   return caseId != null ? (
     <>
       {userPermissions != null && !userPermissions?.crud && userPermissions?.read && (
-        <CaseCallOut title={infoReadSavedObject.title} message={infoReadSavedObject.description} />
+        <CaseCallOut title={savedObjectReadOnly.title} message={savedObjectReadOnly.description} />
       )}
       <CaseView caseId={caseId} userCanCrud={userPermissions?.crud ?? false} />
       <SpyRoute />
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/case_data.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/case_data.tsx
new file mode 100644
index 0000000000000..64c6276fc1be2
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/case_data.tsx
@@ -0,0 +1,226 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { CaseProps } from '../case_view';
+import { Case, Comment, SortFieldCase } from '../../../../containers/case/types';
+import { UseGetCasesState } from '../../../../containers/case/use_get_cases';
+import { UserAction, UserActionField } from '../../../../../../../../plugins/case/common/api/cases';
+
+const updateCase = jest.fn();
+const fetchCase = jest.fn();
+
+const basicCaseId = 'basic-case-id';
+const basicCommentId = 'basic-comment-id';
+const basicCreatedAt = '2020-02-20T23:06:33.798Z';
+const elasticUser = {
+  fullName: 'Leslie Knope',
+  username: 'lknope',
+  email: 'leslie.knope@elastic.co',
+};
+
+export const basicComment: Comment = {
+  comment: 'Solve this fast!',
+  id: basicCommentId,
+  createdAt: basicCreatedAt,
+  createdBy: elasticUser,
+  pushedAt: null,
+  pushedBy: null,
+  updatedAt: '2020-02-20T23:06:33.798Z',
+  updatedBy: {
+    username: 'elastic',
+  },
+  version: 'WzQ3LDFc',
+};
+
+export const basicCase: Case = {
+  closedAt: null,
+  closedBy: null,
+  id: basicCaseId,
+  comments: [basicComment],
+  createdAt: '2020-02-13T19:44:23.627Z',
+  createdBy: elasticUser,
+  description: 'Security banana Issue',
+  externalService: null,
+  status: 'open',
+  tags: ['defacement'],
+  title: 'Another horrible breach!!',
+  totalComment: 1,
+  updatedAt: '2020-02-19T15:02:57.995Z',
+  updatedBy: {
+    username: 'elastic',
+  },
+  version: 'WzQ3LDFd',
+};
+
+export const caseProps: CaseProps = {
+  caseId: basicCaseId,
+  userCanCrud: true,
+  caseData: basicCase,
+  fetchCase,
+  updateCase,
+};
+
+export const caseClosedProps: CaseProps = {
+  ...caseProps,
+  caseData: {
+    ...caseProps.caseData,
+    closedAt: '2020-02-20T23:06:33.798Z',
+    closedBy: {
+      username: 'elastic',
+    },
+    status: 'closed',
+  },
+};
+
+export const basicCaseClosed: Case = {
+  ...caseClosedProps.caseData,
+};
+
+const basicAction = {
+  actionAt: basicCreatedAt,
+  actionBy: elasticUser,
+  oldValue: null,
+  newValue: 'what a cool value',
+  caseId: basicCaseId,
+  commentId: null,
+};
+export const caseUserActions = [
+  {
+    ...basicAction,
+    actionBy: elasticUser,
+    actionField: ['comment'],
+    action: 'create',
+    actionId: 'tt',
+  },
+];
+
+export const useGetCasesMockState: UseGetCasesState = {
+  data: {
+    countClosedCases: 0,
+    countOpenCases: 5,
+    cases: [
+      basicCase,
+      {
+        closedAt: null,
+        closedBy: null,
+        id: '362a5c10-4e99-11ea-9290-35d05cb55c15',
+        createdAt: '2020-02-13T19:44:13.328Z',
+        createdBy: { username: 'elastic' },
+        comments: [],
+        description: 'Security banana Issue',
+        externalService: {
+          pushedAt: '2020-02-13T19:45:01.901Z',
+          pushedBy: 'elastic',
+          connectorId: 'string',
+          connectorName: 'string',
+          externalId: 'string',
+          externalTitle: 'string',
+          externalUrl: 'string',
+        },
+        status: 'open',
+        tags: ['phishing'],
+        title: 'Bad email',
+        totalComment: 0,
+        updatedAt: '2020-02-13T15:45:01.901Z',
+        updatedBy: { username: 'elastic' },
+        version: 'WzQ3LDFd',
+      },
+      {
+        closedAt: null,
+        closedBy: null,
+        id: '34f8b9e0-4e99-11ea-9290-35d05cb55c15',
+        createdAt: '2020-02-13T19:44:11.328Z',
+        createdBy: { username: 'elastic' },
+        comments: [],
+        description: 'Security banana Issue',
+        externalService: {
+          pushedAt: '2020-02-13T19:45:01.901Z',
+          pushedBy: 'elastic',
+          connectorId: 'string',
+          connectorName: 'string',
+          externalId: 'string',
+          externalTitle: 'string',
+          externalUrl: 'string',
+        },
+        status: 'open',
+        tags: ['phishing'],
+        title: 'Bad email',
+        totalComment: 0,
+        updatedAt: '2020-02-14T19:45:01.901Z',
+        updatedBy: { username: 'elastic' },
+        version: 'WzQ3LDFd',
+      },
+      {
+        closedAt: '2020-02-13T19:44:13.328Z',
+        closedBy: { username: 'elastic' },
+        id: '31890e90-4e99-11ea-9290-35d05cb55c15',
+        createdAt: '2020-02-13T19:44:05.563Z',
+        createdBy: { username: 'elastic' },
+        comments: [],
+        description: 'Security banana Issue',
+        externalService: null,
+        status: 'closed',
+        tags: ['phishing'],
+        title: 'Uh oh',
+        totalComment: 0,
+        updatedAt: null,
+        updatedBy: null,
+        version: 'WzQ3LDFd',
+      },
+      {
+        closedAt: null,
+        closedBy: null,
+        id: '2f5b3210-4e99-11ea-9290-35d05cb55c15',
+        createdAt: '2020-02-13T19:44:01.901Z',
+        createdBy: { username: 'elastic' },
+        comments: [],
+        description: 'Security banana Issue',
+        externalService: null,
+        status: 'open',
+        tags: ['phishing'],
+        title: 'Uh oh',
+        totalComment: 0,
+        updatedAt: null,
+        updatedBy: null,
+        version: 'WzQ3LDFd',
+      },
+    ],
+    page: 1,
+    perPage: 5,
+    total: 10,
+  },
+  loading: [],
+  selectedCases: [],
+  isError: false,
+  queryParams: {
+    page: 1,
+    perPage: 5,
+    sortField: SortFieldCase.createdAt,
+    sortOrder: 'desc',
+  },
+  filterOptions: { search: '', reporters: [], tags: [], status: 'open' },
+};
+
+const basicPush = {
+  connector_id: 'connector_id',
+  connector_name: 'connector name',
+  external_id: 'external_id',
+  external_title: 'external title',
+  external_url: 'basicPush.com',
+  pushed_at: basicCreatedAt,
+  pushed_by: elasticUser,
+};
+export const getUserAction = (af: UserActionField, a: UserAction) => ({
+  ...basicAction,
+  actionId: `${af[0]}-${a}`,
+  actionField: af,
+  action: a,
+  commentId: af[0] === 'comment' ? basicCommentId : null,
+  newValue:
+    a === 'push-to-service' && af[0] === 'pushed'
+      ? JSON.stringify(basicPush)
+      : basicAction.newValue,
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/form.ts b/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/form.ts
new file mode 100644
index 0000000000000..9d2ac29bc47d7
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/form.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+export const mockFormHook = {
+  isSubmitted: false,
+  isSubmitting: false,
+  isValid: true,
+  submit: jest.fn(),
+  subscribe: jest.fn(),
+  setFieldValue: jest.fn(),
+  setFieldErrors: jest.fn(),
+  getFields: jest.fn(),
+  getFormData: jest.fn(),
+  getFieldDefaultValue: jest.fn(),
+  /* Returns a list of all errors in the form */
+  getErrors: jest.fn(),
+  reset: jest.fn(),
+  __options: {},
+  __formData$: {},
+  __addField: jest.fn(),
+  __removeField: jest.fn(),
+  __validateFields: jest.fn(),
+  __updateFormDataAt: jest.fn(),
+  __readFieldConfigFromSchema: jest.fn(),
+};
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const getFormMock = (sampleData: any) => ({
+  ...mockFormHook,
+  submit: () =>
+    Promise.resolve({
+      data: sampleData,
+      isValid: true,
+    }),
+  getFormData: () => sampleData,
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/router.ts b/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/router.ts
new file mode 100644
index 0000000000000..a20ab00852a36
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/__mock__/router.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { Router } from 'react-router-dom';
+// eslint-disable-next-line @kbn/eslint/module_migration
+import routeData from 'react-router';
+type Action = 'PUSH' | 'POP' | 'REPLACE';
+const pop: Action = 'POP';
+const location = {
+  pathname: '/network',
+  search: '',
+  state: '',
+  hash: '',
+};
+export const mockHistory = {
+  length: 2,
+  location,
+  action: pop,
+  push: jest.fn(),
+  replace: jest.fn(),
+  go: jest.fn(),
+  goBack: jest.fn(),
+  goForward: jest.fn(),
+  block: jest.fn(),
+  createHref: jest.fn(),
+  listen: jest.fn(),
+};
+
+export const mockLocation = {
+  pathname: '/welcome',
+  hash: '',
+  search: '',
+  state: '',
+};
+
+export { Router, routeData };
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.test.tsx
new file mode 100644
index 0000000000000..74f6411f17fa0
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.test.tsx
@@ -0,0 +1,144 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { AddComment } from './';
+import { TestProviders } from '../../../../mock';
+import { getFormMock } from '../__mock__/form';
+import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
+
+import { useInsertTimeline } from '../../../../components/timeline/insert_timeline_popover/use_insert_timeline';
+import { usePostComment } from '../../../../containers/case/use_post_comment';
+import { useForm } from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form';
+import { wait } from '../../../../lib/helpers';
+jest.mock(
+  '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'
+);
+jest.mock('../../../../components/timeline/insert_timeline_popover/use_insert_timeline');
+jest.mock('../../../../containers/case/use_post_comment');
+
+export const useFormMock = useForm as jest.Mock;
+
+const useInsertTimelineMock = useInsertTimeline as jest.Mock;
+const usePostCommentMock = usePostComment as jest.Mock;
+
+const onCommentSaving = jest.fn();
+const onCommentPosted = jest.fn();
+const postComment = jest.fn();
+const handleCursorChange = jest.fn();
+const handleOnTimelineChange = jest.fn();
+
+const addCommentProps = {
+  caseId: '1234',
+  disabled: false,
+  insertQuote: null,
+  onCommentSaving,
+  onCommentPosted,
+  showLoading: false,
+};
+
+const defaultInsertTimeline = {
+  cursorPosition: {
+    start: 0,
+    end: 0,
+  },
+  handleCursorChange,
+  handleOnTimelineChange,
+};
+
+const defaultPostCommment = {
+  isLoading: false,
+  isError: false,
+  postComment,
+};
+const sampleData = {
+  comment: 'what a cool comment',
+};
+describe('AddComment ', () => {
+  const formHookMock = getFormMock(sampleData);
+
+  beforeEach(() => {
+    jest.resetAllMocks();
+    useInsertTimelineMock.mockImplementation(() => defaultInsertTimeline);
+    usePostCommentMock.mockImplementation(() => defaultPostCommment);
+    useFormMock.mockImplementation(() => ({ form: formHookMock }));
+    jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation);
+  });
+
+  it('should post comment on submit click', async () => {
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <AddComment {...addCommentProps} />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find(`[data-test-subj="add-comment"]`).exists()).toBeTruthy();
+    expect(wrapper.find(`[data-test-subj="loading-spinner"]`).exists()).toBeFalsy();
+
+    wrapper
+      .find(`[data-test-subj="submit-comment"]`)
+      .first()
+      .simulate('click');
+    await wait();
+    expect(onCommentSaving).toBeCalled();
+    expect(postComment).toBeCalledWith(sampleData, onCommentPosted);
+    expect(formHookMock.reset).toBeCalled();
+  });
+
+  it('should render spinner and disable submit when loading', () => {
+    usePostCommentMock.mockImplementation(() => ({ ...defaultPostCommment, isLoading: true }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <AddComment {...{ ...addCommentProps, showLoading: true }} />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find(`[data-test-subj="loading-spinner"]`).exists()).toBeTruthy();
+    expect(
+      wrapper
+        .find(`[data-test-subj="submit-comment"]`)
+        .first()
+        .prop('isDisabled')
+    ).toBeTruthy();
+  });
+
+  it('should disable submit button when disabled prop passed', () => {
+    usePostCommentMock.mockImplementation(() => ({ ...defaultPostCommment, isLoading: true }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <AddComment {...{ ...addCommentProps, disabled: true }} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="submit-comment"]`)
+        .first()
+        .prop('isDisabled')
+    ).toBeTruthy();
+  });
+
+  it('should insert a quote if one is available', () => {
+    const sampleQuote = 'what a cool quote';
+    mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <AddComment {...{ ...addCommentProps, insertQuote: sampleQuote }} />
+        </Router>
+      </TestProviders>
+    );
+
+    expect(formHookMock.setFieldValue).toBeCalledWith(
+      'comment',
+      `${sampleData.comment}\n\n${sampleQuote}`
+    );
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.tsx
index ecc57c50e28eb..eaba708948a99 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/add_comment/index.tsx
@@ -71,10 +71,9 @@ export const AddComment = React.memo<AddCommentProps>(
         form.reset();
       }
     }, [form, onCommentPosted, onCommentSaving]);
-
     return (
       <span id="add-comment-permLink">
-        {isLoading && showLoading && <MySpinner size="xl" />}
+        {isLoading && showLoading && <MySpinner data-test-subj="loading-spinner" size="xl" />}
         <Form form={form}>
           <UseField
             path="comment"
@@ -82,11 +81,12 @@ export const AddComment = React.memo<AddCommentProps>(
             componentProps={{
               idAria: 'caseComment',
               isDisabled: isLoading,
-              dataTestSubj: 'caseComment',
+              dataTestSubj: 'add-comment',
               placeholder: i18n.ADD_COMMENT_HELP_TEXT,
               onCursorPositionUpdate: handleCursorChange,
               bottomRightContent: (
                 <EuiButton
+                  data-test-subj="submit-comment"
                   iconType="plusInCircle"
                   isDisabled={isLoading || disabled}
                   isLoading={isLoading}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx
deleted file mode 100644
index d4ec32dfd070b..0000000000000
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { SortFieldCase } from '../../../../../containers/case/types';
-import { UseGetCasesState } from '../../../../../containers/case/use_get_cases';
-
-export const useGetCasesMockState: UseGetCasesState = {
-  data: {
-    countClosedCases: 0,
-    countOpenCases: 5,
-    cases: [
-      {
-        closedAt: null,
-        closedBy: null,
-        id: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15',
-        createdAt: '2020-02-13T19:44:23.627Z',
-        createdBy: { username: 'elastic' },
-        comments: [],
-        description: 'Security banana Issue',
-        externalService: null,
-        status: 'open',
-        tags: ['defacement'],
-        title: 'Another horrible breach',
-        totalComment: 0,
-        updatedAt: null,
-        updatedBy: null,
-        version: 'WzQ3LDFd',
-      },
-      {
-        closedAt: null,
-        closedBy: null,
-        id: '362a5c10-4e99-11ea-9290-35d05cb55c15',
-        createdAt: '2020-02-13T19:44:13.328Z',
-        createdBy: { username: 'elastic' },
-        comments: [],
-        description: 'Security banana Issue',
-        externalService: null,
-        status: 'open',
-        tags: ['phishing'],
-        title: 'Bad email',
-        totalComment: 0,
-        updatedAt: null,
-        updatedBy: null,
-        version: 'WzQ3LDFd',
-      },
-      {
-        closedAt: null,
-        closedBy: null,
-        id: '34f8b9e0-4e99-11ea-9290-35d05cb55c15',
-        createdAt: '2020-02-13T19:44:11.328Z',
-        createdBy: { username: 'elastic' },
-        comments: [],
-        description: 'Security banana Issue',
-        externalService: null,
-        status: 'open',
-        tags: ['phishing'],
-        title: 'Bad email',
-        totalComment: 0,
-        updatedAt: null,
-        updatedBy: null,
-        version: 'WzQ3LDFd',
-      },
-      {
-        closedAt: '2020-02-13T19:44:13.328Z',
-        closedBy: { username: 'elastic' },
-        id: '31890e90-4e99-11ea-9290-35d05cb55c15',
-        createdAt: '2020-02-13T19:44:05.563Z',
-        createdBy: { username: 'elastic' },
-        comments: [],
-        description: 'Security banana Issue',
-        externalService: null,
-        status: 'closed',
-        tags: ['phishing'],
-        title: 'Uh oh',
-        totalComment: 0,
-        updatedAt: null,
-        updatedBy: null,
-        version: 'WzQ3LDFd',
-      },
-      {
-        closedAt: null,
-        closedBy: null,
-        id: '2f5b3210-4e99-11ea-9290-35d05cb55c15',
-        createdAt: '2020-02-13T19:44:01.901Z',
-        createdBy: { username: 'elastic' },
-        comments: [],
-        description: 'Security banana Issue',
-        externalService: null,
-        status: 'open',
-        tags: ['phishing'],
-        title: 'Uh oh',
-        totalComment: 0,
-        updatedAt: null,
-        updatedBy: null,
-        version: 'WzQ3LDFd',
-      },
-    ],
-    page: 1,
-    perPage: 5,
-    total: 10,
-  },
-  loading: [],
-  selectedCases: [],
-  isError: false,
-  queryParams: {
-    page: 1,
-    perPage: 5,
-    sortField: SortFieldCase.createdAt,
-    sortOrder: 'desc',
-  },
-  filterOptions: { search: '', reporters: [], tags: [], status: 'open' },
-};
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.test.tsx
new file mode 100644
index 0000000000000..e008b94ab9e16
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.test.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { ServiceNowColumn } from './columns';
+
+import { useGetCasesMockState } from '../__mock__/case_data';
+
+describe('ServiceNowColumn ', () => {
+  it('Not pushed render', () => {
+    const wrapper = mount(
+      <ServiceNowColumn {...{ theCase: useGetCasesMockState.data.cases[0] }} />
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="case-table-column-external-notPushed"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+  });
+  it('Up to date', () => {
+    const wrapper = mount(
+      <ServiceNowColumn {...{ theCase: useGetCasesMockState.data.cases[1] }} />
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="case-table-column-external-upToDate"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+  });
+  it('Needs update', () => {
+    const wrapper = mount(
+      <ServiceNowColumn {...{ theCase: useGetCasesMockState.data.cases[2] }} />
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="case-table-column-external-requiresUpdate"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx
index 0e12f78e29bc2..e48e5cb0c5959 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx
@@ -114,7 +114,9 @@ export const getCasesColumns = (
     name: i18n.COMMENTS,
     sortable: true,
     render: (totalComment: Case['totalComment']) =>
-      renderStringField(`${totalComment}`, `case-table-column-commentCount`),
+      totalComment != null
+        ? renderStringField(`${totalComment}`, `case-table-column-commentCount`)
+        : getEmptyTagValue(),
   },
   filterStatus === 'open'
     ? {
@@ -150,7 +152,7 @@ export const getCasesColumns = (
         },
       },
   {
-    name: 'ServiceNow Incident',
+    name: i18n.SERVICENOW_INCIDENT,
     render: (theCase: Case) => {
       if (theCase.id != null) {
         return <ServiceNowColumn theCase={theCase} />;
@@ -159,7 +161,7 @@ export const getCasesColumns = (
     },
   },
   {
-    name: 'Actions',
+    name: i18n.ACTIONS,
     actions,
   },
 ];
@@ -168,7 +170,7 @@ interface Props {
   theCase: Case;
 }
 
-const ServiceNowColumn: React.FC<Props> = ({ theCase }) => {
+export const ServiceNowColumn: React.FC<Props> = ({ theCase }) => {
   const handleRenderDataToPush = useCallback(() => {
     const lastCaseUpdate = theCase.updatedAt != null ? new Date(theCase.updatedAt) : null;
     const lastCasePush =
@@ -190,7 +192,9 @@ const ServiceNowColumn: React.FC<Props> = ({ theCase }) => {
         >
           {theCase.externalService?.externalTitle}
         </EuiLink>
-        {hasDataToPush ? i18n.REQUIRES_UPDATE : i18n.UP_TO_DATE}
+        {hasDataToPush
+          ? renderStringField(i18n.REQUIRES_UPDATE, `case-table-column-external-requiresUpdate`)
+          : renderStringField(i18n.UP_TO_DATE, `case-table-column-external-upToDate`)}
       </p>
     );
   }, [theCase]);
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx
index a6da45a8c5bb1..f65736e7cd109 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx
@@ -9,11 +9,15 @@ import { mount } from 'enzyme';
 import moment from 'moment-timezone';
 import { AllCases } from './';
 import { TestProviders } from '../../../../mock';
-import { useGetCasesMockState } from './__mock__';
+import { useGetCasesMockState } from '../__mock__/case_data';
+import * as i18n from './translations';
+
+import { getEmptyTagValue } from '../../../../components/empty_value';
 import { useDeleteCases } from '../../../../containers/case/use_delete_cases';
 import { useGetCases } from '../../../../containers/case/use_get_cases';
 import { useGetCasesStatus } from '../../../../containers/case/use_get_cases_status';
 import { useUpdateCases } from '../../../../containers/case/use_bulk_update_case';
+import { getCasesColumns } from './columns';
 jest.mock('../../../../containers/case/use_bulk_update_case');
 jest.mock('../../../../containers/case/use_delete_cases');
 jest.mock('../../../../containers/case/use_get_cases');
@@ -35,6 +39,7 @@ describe('AllCases', () => {
   const setSelectedCases = jest.fn();
   const updateBulkStatus = jest.fn();
   const fetchCasesStatus = jest.fn();
+  const emptyTag = getEmptyTagValue().props.children;
 
   const defaultGetCases = {
     ...useGetCasesMockState,
@@ -115,7 +120,7 @@ describe('AllCases', () => {
         .find(`[data-test-subj="case-table-column-createdBy"]`)
         .first()
         .text()
-    ).toEqual(useGetCasesMockState.data.cases[0].createdBy.username);
+    ).toEqual(useGetCasesMockState.data.cases[0].createdBy.fullName);
     expect(
       wrapper
         .find(`[data-test-subj="case-table-column-createdAt"]`)
@@ -129,6 +134,39 @@ describe('AllCases', () => {
         .text()
     ).toEqual('Showing 10 cases');
   });
+  it('should render empty fields', () => {
+    useGetCasesMock.mockImplementation(() => ({
+      ...defaultGetCases,
+      data: {
+        ...defaultGetCases.data,
+        cases: [
+          {
+            ...defaultGetCases.data.cases[0],
+            id: null,
+            createdAt: null,
+            createdBy: null,
+            tags: null,
+            title: null,
+            totalComment: null,
+          },
+        ],
+      },
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <AllCases userCanCrud={true} />
+      </TestProviders>
+    );
+    const checkIt = (columnName: string, key: number) => {
+      const column = wrapper.find('[data-test-subj="cases-table"] tbody .euiTableRowCell').at(key);
+      if (columnName === i18n.ACTIONS) {
+        return;
+      }
+      expect(column.find('.euiTableRowCell--hideForDesktop').text()).toEqual(columnName);
+      expect(column.find('span').text()).toEqual(emptyTag);
+    };
+    getCasesColumns([], 'open').map((i, key) => i.name != null && checkIt(`${i.name}`, key));
+  });
   it('should tableHeaderSortButton AllCases', () => {
     const wrapper = mount(
       <TestProviders>
@@ -165,6 +203,30 @@ describe('AllCases', () => {
       version: firstCase.version,
     });
   });
+  it('opens case when row action icon clicked', () => {
+    useGetCasesMock.mockImplementation(() => ({
+      ...defaultGetCases,
+      filterOptions: { ...defaultGetCases.filterOptions, status: 'closed' },
+    }));
+
+    const wrapper = mount(
+      <TestProviders>
+        <AllCases userCanCrud={true} />
+      </TestProviders>
+    );
+    wrapper
+      .find('[data-test-subj="action-open"]')
+      .first()
+      .simulate('click');
+    const firstCase = useGetCasesMockState.data.cases[0];
+    expect(dispatchUpdateCaseProperty).toBeCalledWith({
+      caseId: firstCase.id,
+      updateKey: 'status',
+      updateValue: 'open',
+      refetchCasesStatus: fetchCasesStatus,
+      version: firstCase.version,
+    });
+  });
   it('Bulk delete', () => {
     useGetCasesMock.mockImplementation(() => ({
       ...defaultGetCases,
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.test.tsx
new file mode 100644
index 0000000000000..615d052347203
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.test.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { CasesTableFilters } from './table_filters';
+import { TestProviders } from '../../../../mock';
+
+import { useGetTags } from '../../../../containers/case/use_get_tags';
+import { useGetReporters } from '../../../../containers/case/use_get_reporters';
+import { DEFAULT_FILTER_OPTIONS } from '../../../../containers/case/use_get_cases';
+jest.mock('../../../../components/timeline/insert_timeline_popover/use_insert_timeline');
+jest.mock('../../../../containers/case/use_get_reporters');
+jest.mock('../../../../containers/case/use_get_tags');
+
+const onFilterChanged = jest.fn();
+const fetchReporters = jest.fn();
+
+const props = {
+  countClosedCases: 1234,
+  countOpenCases: 99,
+  onFilterChanged,
+  initial: DEFAULT_FILTER_OPTIONS,
+};
+describe('CasesTableFilters ', () => {
+  beforeEach(() => {
+    jest.resetAllMocks();
+    (useGetTags as jest.Mock).mockReturnValue({ tags: ['coke', 'pepsi'] });
+    (useGetReporters as jest.Mock).mockReturnValue({
+      reporters: ['casetester'],
+      respReporters: [{ username: 'casetester' }],
+      isLoading: true,
+      isError: false,
+      fetchReporters,
+    });
+  });
+  it('should render the initial case count', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <CasesTableFilters {...props} />
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="open-case-count"]`)
+        .last()
+        .text()
+    ).toEqual('Open cases (99)');
+    expect(
+      wrapper
+        .find(`[data-test-subj="closed-case-count"]`)
+        .last()
+        .text()
+    ).toEqual('Closed cases (1234)');
+  });
+  it('should call onFilterChange when tags change', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <CasesTableFilters {...props} />
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="options-filter-popover-button-Tags"]`)
+      .last()
+      .simulate('click');
+    wrapper
+      .find(`[data-test-subj="options-filter-popover-item-0"]`)
+      .last()
+      .simulate('click');
+
+    expect(onFilterChanged).toBeCalledWith({ tags: ['coke'] });
+  });
+  it('should call onFilterChange when reporters change', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <CasesTableFilters {...props} />
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="options-filter-popover-button-Reporter"]`)
+      .last()
+      .simulate('click');
+
+    wrapper
+      .find(`[data-test-subj="options-filter-popover-item-0"]`)
+      .last()
+      .simulate('click');
+
+    expect(onFilterChanged).toBeCalledWith({ reporters: [{ username: 'casetester' }] });
+  });
+  it('should call onFilterChange when search changes', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <CasesTableFilters {...props} />
+      </TestProviders>
+    );
+
+    wrapper
+      .find(`[data-test-subj="search-cases"]`)
+      .last()
+      .simulate('keyup', { keyCode: 13, target: { value: 'My search' } });
+    expect(onFilterChanged).toBeCalledWith({ search: 'My search' });
+  });
+  it('should call onFilterChange when status toggled', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <CasesTableFilters {...props} />
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="closed-case-count"]`)
+      .last()
+      .simulate('click');
+
+    expect(onFilterChanged).toBeCalledWith({ status: 'closed' });
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.tsx
index a344dd7891010..da477a56c0a22 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/table_filters.tsx
@@ -42,7 +42,7 @@ const CasesTableFiltersComponent = ({
   onFilterChanged,
   initial = defaultInitial,
 }: CasesTableFiltersProps) => {
-  const [selectedReporters, setselectedReporters] = useState(
+  const [selectedReporters, setSelectedReporters] = useState(
     initial.reporters.map(r => r.full_name ?? r.username ?? '')
   );
   const [search, setSearch] = useState(initial.search);
@@ -54,7 +54,7 @@ const CasesTableFiltersComponent = ({
   const handleSelectedReporters = useCallback(
     newReporters => {
       if (!isEqual(newReporters, selectedReporters)) {
-        setselectedReporters(newReporters);
+        setSelectedReporters(newReporters);
         const reportersObj = respReporters.filter(
           r => newReporters.includes(r.username) || newReporters.includes(r.full_name)
         );
@@ -97,6 +97,7 @@ const CasesTableFiltersComponent = ({
       <EuiFlexItem grow={true}>
         <EuiFieldSearch
           aria-label={i18n.SEARCH_CASES}
+          data-test-subj="search-cases"
           fullWidth
           incremental={false}
           placeholder={i18n.SEARCH_PLACEHOLDER}
@@ -107,6 +108,7 @@ const CasesTableFiltersComponent = ({
       <EuiFlexItem grow={false}>
         <EuiFilterGroup>
           <EuiFilterButton
+            data-test-subj="open-case-count"
             withNext
             hasActiveFilters={showOpenCases}
             onClick={handleToggleFilter.bind(null, true)}
@@ -115,6 +117,7 @@ const CasesTableFiltersComponent = ({
             {countOpenCases != null ? ` (${countOpenCases})` : ''}
           </EuiFilterButton>
           <EuiFilterButton
+            data-test-subj="closed-case-count"
             hasActiveFilters={!showOpenCases}
             onClick={handleToggleFilter.bind(null, false)}
           >
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/translations.ts b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/translations.ts
index 1bee96bc23fff..d3dcfa50ecfa5 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/translations.ts
@@ -46,6 +46,10 @@ export const BULK_ACTIONS = i18n.translate('xpack.siem.case.caseTable.bulkAction
   defaultMessage: 'Bulk actions',
 });
 
+export const SERVICENOW_INCIDENT = i18n.translate('xpack.siem.case.caseTable.snIncident', {
+  defaultMessage: 'ServiceNow Incident',
+});
+
 export const SEARCH_PLACEHOLDER = i18n.translate('xpack.siem.case.caseTable.searchPlaceholder', {
   defaultMessage: 'e.g. case name',
 });
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/callout/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/callout/helpers.tsx
index 929e8640dceb6..3237104274473 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/callout/helpers.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/callout/helpers.tsx
@@ -6,7 +6,7 @@
 
 import * as i18n from './translations';
 
-export const getSavedObjectReadOnly = () => ({
+export const savedObjectReadOnly = {
   title: i18n.READ_ONLY_SAVED_OBJECT_TITLE,
   description: i18n.READ_ONLY_SAVED_OBJECT_MSG,
-});
+};
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.test.tsx
new file mode 100644
index 0000000000000..126ea13e96af6
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.test.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { CaseCallOut } from './';
+
+const defaultProps = {
+  title: 'hey title',
+};
+
+describe('CaseCallOut ', () => {
+  it('Renders single message callout', () => {
+    const props = {
+      ...defaultProps,
+      message: 'we have one message',
+    };
+    const wrapper = mount(<CaseCallOut {...props} />);
+    expect(
+      wrapper
+        .find(`[data-test-subj="callout-message"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+    expect(
+      wrapper
+        .find(`[data-test-subj="callout-messages"]`)
+        .last()
+        .exists()
+    ).toBeFalsy();
+  });
+  it('Renders multi message callout', () => {
+    const props = {
+      ...defaultProps,
+      messages: [
+        { ...defaultProps, description: <p>{'we have two messages'}</p> },
+        { ...defaultProps, description: <p>{'for real'}</p> },
+      ],
+    };
+    const wrapper = mount(<CaseCallOut {...props} />);
+    expect(
+      wrapper
+        .find(`[data-test-subj="callout-message"]`)
+        .last()
+        .exists()
+    ).toBeFalsy();
+    expect(
+      wrapper
+        .find(`[data-test-subj="callout-messages"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+  });
+  it('Dismisses callout', () => {
+    const props = {
+      ...defaultProps,
+      message: 'we have one message',
+    };
+    const wrapper = mount(<CaseCallOut {...props} />);
+    expect(wrapper.find(`[data-test-subj="case-call-out"]`).exists()).toBeTruthy();
+    wrapper
+      .find(`[data-test-subj="callout-dismiss"]`)
+      .last()
+      .simulate('click');
+    expect(wrapper.find(`[data-test-subj="case-call-out"]`).exists()).toBeFalsy();
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.tsx
index 30a95db2d82a5..0fc93af7f318d 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/callout/index.tsx
@@ -24,10 +24,12 @@ const CaseCallOutComponent = ({ title, message, messages }: CaseCallOutProps) =>
 
   return showCallOut ? (
     <>
-      <EuiCallOut title={title} color="primary" iconType="gear">
-        {!isEmpty(messages) && <EuiDescriptionList listItems={messages} />}
-        {!isEmpty(message) && <p>{message}</p>}
-        <EuiButton color="primary" onClick={handleCallOut}>
+      <EuiCallOut title={title} color="primary" iconType="gear" data-test-subj="case-call-out">
+        {!isEmpty(messages) && (
+          <EuiDescriptionList data-test-subj="callout-messages" listItems={messages} />
+        )}
+        {!isEmpty(message) && <p data-test-subj="callout-message">{message}</p>}
+        <EuiButton data-test-subj="callout-dismiss" color="primary" onClick={handleCallOut}>
           {i18n.DISMISS_CALLOUT}
         </EuiButton>
       </EuiCallOut>
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_status/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_status/index.tsx
index 2b16dfa150d61..718eb95767f2e 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_status/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_status/index.tsx
@@ -84,7 +84,7 @@ const CaseStatusComp: React.FC<CaseStatusProps> = ({
     <EuiFlexItem grow={false}>
       <EuiFlexGroup gutterSize="l" alignItems="center">
         <EuiFlexItem>
-          <EuiButtonEmpty iconType="refresh" onClick={onRefresh}>
+          <EuiButtonEmpty data-test-subj="case-refresh" iconType="refresh" onClick={onRefresh}>
             {i18n.CASE_REFRESH}
           </EuiButtonEmpty>
         </EuiFlexItem>
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx
deleted file mode 100644
index 0e57326707e97..0000000000000
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { CaseProps } from '../index';
-import { Case } from '../../../../../containers/case/types';
-
-const updateCase = jest.fn();
-const fetchCase = jest.fn();
-
-export const caseProps: CaseProps = {
-  caseId: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15',
-  userCanCrud: true,
-  caseData: {
-    closedAt: null,
-    closedBy: null,
-    id: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15',
-    comments: [
-      {
-        comment: 'Solve this fast!',
-        id: 'a357c6a0-5435-11ea-b427-fb51a1fcb7b8',
-        createdAt: '2020-02-20T23:06:33.798Z',
-        createdBy: {
-          fullName: 'Steph Milovic',
-          username: 'smilovic',
-          email: 'notmyrealemailfool@elastic.co',
-        },
-        pushedAt: null,
-        pushedBy: null,
-        updatedAt: '2020-02-20T23:06:33.798Z',
-        updatedBy: {
-          username: 'elastic',
-        },
-        version: 'WzQ3LDFd',
-      },
-    ],
-    createdAt: '2020-02-13T19:44:23.627Z',
-    createdBy: { fullName: null, email: 'testemail@elastic.co', username: 'elastic' },
-    description: 'Security banana Issue',
-    externalService: null,
-    status: 'open',
-    tags: ['defacement'],
-    title: 'Another horrible breach!!',
-    totalComment: 1,
-    updatedAt: '2020-02-19T15:02:57.995Z',
-    updatedBy: {
-      username: 'elastic',
-    },
-    version: 'WzQ3LDFd',
-  },
-  fetchCase,
-  updateCase,
-};
-
-export const caseClosedProps: CaseProps = {
-  ...caseProps,
-  caseData: {
-    ...caseProps.caseData,
-    closedAt: '2020-02-20T23:06:33.798Z',
-    closedBy: {
-      username: 'elastic',
-    },
-    status: 'closed',
-  },
-};
-
-export const data: Case = {
-  ...caseProps.caseData,
-};
-
-export const dataClosed: Case = {
-  ...caseClosedProps.caseData,
-};
-
-export const caseUserActions = [
-  {
-    actionField: ['comment'],
-    action: 'create',
-    actionAt: '2020-03-20T17:10:09.814Z',
-    actionBy: {
-      fullName: 'Steph Milovic',
-      username: 'smilovic',
-      email: 'notmyrealemailfool@elastic.co',
-    },
-    newValue: 'Solve this fast!',
-    oldValue: null,
-    actionId: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15',
-    caseId: '9b833a50-6acd-11ea-8fad-af86b1071bd9',
-    commentId: 'a357c6a0-5435-11ea-b427-fb51a1fcb7b8',
-  },
-];
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.test.tsx
index 49f5f44cba271..8a25a2121104d 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.test.tsx
@@ -9,7 +9,7 @@ import { mount } from 'enzyme';
 
 import { useDeleteCases } from '../../../../containers/case/use_delete_cases';
 import { TestProviders } from '../../../../mock';
-import { data } from './__mock__';
+import { basicCase } from '../__mock__/case_data';
 import { CaseViewActions } from './actions';
 jest.mock('../../../../containers/case/use_delete_cases');
 const useDeleteCasesMock = useDeleteCases as jest.Mock;
@@ -34,7 +34,7 @@ describe('CaseView actions', () => {
   it('clicking trash toggles modal', () => {
     const wrapper = mount(
       <TestProviders>
-        <CaseViewActions caseData={data} />
+        <CaseViewActions caseData={basicCase} />
       </TestProviders>
     );
 
@@ -54,12 +54,14 @@ describe('CaseView actions', () => {
     }));
     const wrapper = mount(
       <TestProviders>
-        <CaseViewActions caseData={data} />
+        <CaseViewActions caseData={basicCase} />
       </TestProviders>
     );
 
     expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeTruthy();
     wrapper.find('button[data-test-subj="confirmModalConfirmButton"]').simulate('click');
-    expect(handleOnDeleteConfirm.mock.calls[0][0]).toEqual([{ id: data.id, title: data.title }]);
+    expect(handleOnDeleteConfirm.mock.calls[0][0]).toEqual([
+      { id: basicCase.id, title: basicCase.title },
+    ]);
   });
 });
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.tsx
index 0b08b866df964..216180eb2cf0a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/actions.tsx
@@ -40,7 +40,6 @@ const CaseViewActionsComponent: React.FC<CaseViewActions> = ({ caseData, disable
     ),
     [isDisplayConfirmDeleteModal, caseData]
   );
-  // TO DO refactor each of these const's into their own components
   const propertyActions = useMemo(
     () => [
       {
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx
index 3f5b3a3127177..3721a5a727ca5 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx
@@ -5,56 +5,43 @@
  */
 
 import React from 'react';
-import { Router } from 'react-router-dom';
 import { mount } from 'enzyme';
-/* eslint-disable @kbn/eslint/module_migration */
-import routeData from 'react-router';
-/* eslint-enable @kbn/eslint/module_migration */
-import { CaseComponent } from './';
-import { caseProps, caseClosedProps, data, dataClosed, caseUserActions } from './__mock__';
+
+import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
+import { CaseComponent, CaseView } from './';
+import {
+  basicCaseClosed,
+  caseClosedProps,
+  caseProps,
+  caseUserActions,
+} from '../__mock__/case_data';
 import { TestProviders } from '../../../../mock';
 import { useUpdateCase } from '../../../../containers/case/use_update_case';
+import { useGetCase } from '../../../../containers/case/use_get_case';
 import { useGetCaseUserActions } from '../../../../containers/case/use_get_case_user_actions';
 import { wait } from '../../../../lib/helpers';
 import { usePushToService } from '../use_push_to_service';
 jest.mock('../../../../containers/case/use_update_case');
 jest.mock('../../../../containers/case/use_get_case_user_actions');
+jest.mock('../../../../containers/case/use_get_case');
 jest.mock('../use_push_to_service');
 const useUpdateCaseMock = useUpdateCase as jest.Mock;
 const useGetCaseUserActionsMock = useGetCaseUserActions as jest.Mock;
 const usePushToServiceMock = usePushToService as jest.Mock;
-type Action = 'PUSH' | 'POP' | 'REPLACE';
-const pop: Action = 'POP';
-const location = {
-  pathname: '/network',
-  search: '',
-  state: '',
-  hash: '',
-};
-const mockHistory = {
-  length: 2,
-  location,
-  action: pop,
-  push: jest.fn(),
-  replace: jest.fn(),
-  go: jest.fn(),
-  goBack: jest.fn(),
-  goForward: jest.fn(),
-  block: jest.fn(),
-  createHref: jest.fn(),
-  listen: jest.fn(),
-};
-
-const mockLocation = {
-  pathname: '/welcome',
-  hash: '',
-  search: '',
-  state: '',
-};
 
 describe('CaseView ', () => {
   const updateCaseProperty = jest.fn();
   const fetchCaseUserActions = jest.fn();
+  const fetchCase = jest.fn();
+  const updateCase = jest.fn();
+  const data = caseProps.caseData;
+  const defaultGetCase = {
+    isLoading: false,
+    isError: false,
+    data,
+    updateCase,
+    fetchCase,
+  };
   /* eslint-disable no-console */
   // Silence until enzyme fixed to use ReactTestUtils.act()
   const originalError = console.error;
@@ -84,17 +71,23 @@ describe('CaseView ', () => {
     participants: [data.createdBy],
   };
 
-  const defaultUsePushToServiceMock = {
-    pushButton: <>{'Hello Button'}</>,
-    pushCallouts: null,
-  };
-
   beforeEach(() => {
     jest.resetAllMocks();
     useUpdateCaseMock.mockImplementation(() => defaultUpdateCaseState);
     jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation);
     useGetCaseUserActionsMock.mockImplementation(() => defaultUseGetCaseUserActions);
-    usePushToServiceMock.mockImplementation(() => defaultUsePushToServiceMock);
+    usePushToServiceMock.mockImplementation(({ updateCase: updateCaseMockCall }) => ({
+      pushButton: (
+        <button
+          data-test-subj="mock-button"
+          onClick={() => updateCaseMockCall(caseProps.caseData)}
+          type="button"
+        >
+          {'Hello Button'}
+        </button>
+      ),
+      pushCallouts: null,
+    }));
   });
 
   it('should render CaseComponent', async () => {
@@ -120,7 +113,7 @@ describe('CaseView ', () => {
     ).toEqual(data.status);
     expect(
       wrapper
-        .find(`[data-test-subj="case-view-tag-list"] .euiBadge__text`)
+        .find(`[data-test-subj="case-view-tag-list"] [data-test-subj="case-tag"]`)
         .first()
         .text()
     ).toEqual(data.tags[0]);
@@ -139,7 +132,7 @@ describe('CaseView ', () => {
     ).toEqual(data.createdAt);
     expect(
       wrapper
-        .find(`[data-test-subj="case-view-description"]`)
+        .find(`[data-test-subj="description-action"] [data-test-subj="user-action-markdown"]`)
         .first()
         .prop('raw')
     ).toEqual(data.description);
@@ -148,7 +141,7 @@ describe('CaseView ', () => {
   it('should show closed indicators in header when case is closed', async () => {
     useUpdateCaseMock.mockImplementation(() => ({
       ...defaultUpdateCaseState,
-      caseData: dataClosed,
+      caseData: basicCaseClosed,
     }));
     const wrapper = mount(
       <TestProviders>
@@ -164,13 +157,13 @@ describe('CaseView ', () => {
         .find(`[data-test-subj="case-view-closedAt"]`)
         .first()
         .prop('value')
-    ).toEqual(dataClosed.closedAt);
+    ).toEqual(basicCaseClosed.closedAt);
     expect(
       wrapper
         .find(`[data-test-subj="case-view-status"]`)
         .first()
         .text()
-    ).toEqual(dataClosed.status);
+    ).toEqual(basicCaseClosed.status);
   });
 
   it('should dispatch update state when button is toggled', async () => {
@@ -188,7 +181,12 @@ describe('CaseView ', () => {
     expect(updateCaseProperty).toHaveBeenCalled();
   });
 
-  it('should render comments', async () => {
+  it('should display EditableTitle isLoading', () => {
+    useUpdateCaseMock.mockImplementation(() => ({
+      ...defaultUpdateCaseState,
+      isLoading: true,
+      updateKey: 'title',
+    }));
     const wrapper = mount(
       <TestProviders>
         <Router history={mockHistory}>
@@ -196,32 +194,230 @@ describe('CaseView ', () => {
         </Router>
       </TestProviders>
     );
-    await wait();
     expect(
       wrapper
-        .find(
-          `div[data-test-subj="user-action-${data.comments[0].id}-avatar"] [data-test-subj="user-action-avatar"]`
-        )
+        .find('[data-test-subj="editable-title-loading"]')
+        .first()
+        .exists()
+    ).toBeTruthy();
+    expect(
+      wrapper
+        .find('[data-test-subj="editable-title-edit-icon"]')
         .first()
-        .prop('name')
-    ).toEqual(data.comments[0].createdBy.fullName);
+        .exists()
+    ).toBeFalsy();
+  });
 
+  it('should display Toggle Status isLoading', () => {
+    useUpdateCaseMock.mockImplementation(() => ({
+      ...defaultUpdateCaseState,
+      isLoading: true,
+      updateKey: 'status',
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseComponent {...caseProps} />
+        </Router>
+      </TestProviders>
+    );
     expect(
       wrapper
-        .find(
-          `div[data-test-subj="user-action-${data.comments[0].id}"] [data-test-subj="user-action-title"] strong`
-        )
+        .find('[data-test-subj="toggle-case-status"]')
         .first()
-        .text()
-    ).toEqual(data.comments[0].createdBy.username);
+        .prop('isLoading')
+    ).toBeTruthy();
+  });
 
+  it('should display description isLoading', () => {
+    useUpdateCaseMock.mockImplementation(() => ({
+      ...defaultUpdateCaseState,
+      isLoading: true,
+      updateKey: 'description',
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseComponent {...caseProps} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find('[data-test-subj="description-action"] [data-test-subj="user-action-title-loading"]')
+        .first()
+        .exists()
+    ).toBeTruthy();
+    expect(
+      wrapper
+        .find('[data-test-subj="description-action"] [data-test-subj="property-actions"]')
+        .first()
+        .exists()
+    ).toBeFalsy();
+  });
+
+  it('should display tags isLoading', () => {
+    useUpdateCaseMock.mockImplementation(() => ({
+      ...defaultUpdateCaseState,
+      isLoading: true,
+      updateKey: 'tags',
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseComponent {...caseProps} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find('[data-test-subj="case-view-tag-list"] [data-test-subj="tag-list-loading"]')
+        .first()
+        .exists()
+    ).toBeTruthy();
     expect(
       wrapper
-        .find(
-          `div[data-test-subj="user-action-${data.comments[0].id}"] [data-test-subj="markdown"]`
-        )
+        .find('[data-test-subj="tag-list-edit"]')
         .first()
-        .prop('source')
-    ).toEqual(data.comments[0].comment);
+        .exists()
+    ).toBeFalsy();
+  });
+
+  it('should update title', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseComponent {...caseProps} />
+        </Router>
+      </TestProviders>
+    );
+    const newTitle = 'The new title';
+    wrapper
+      .find(`[data-test-subj="editable-title-edit-icon"]`)
+      .first()
+      .simulate('click');
+    wrapper.update();
+    wrapper
+      .find(`[data-test-subj="editable-title-input-field"]`)
+      .last()
+      .simulate('change', { target: { value: newTitle } });
+
+    wrapper.update();
+    wrapper
+      .find(`[data-test-subj="editable-title-submit-btn"]`)
+      .first()
+      .simulate('click');
+
+    wrapper.update();
+    const updateObject = updateCaseProperty.mock.calls[0][0];
+    expect(updateObject.updateKey).toEqual('title');
+    expect(updateObject.updateValue).toEqual(newTitle);
+  });
+
+  it('should push updates on button click', async () => {
+    useGetCaseUserActionsMock.mockImplementation(() => ({
+      ...defaultUseGetCaseUserActions,
+      hasDataToPush: true,
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseComponent {...{ ...caseProps, updateCase }} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find('[data-test-subj="has-data-to-push-button"]')
+        .first()
+        .exists()
+    ).toBeTruthy();
+    wrapper
+      .find('[data-test-subj="mock-button"]')
+      .first()
+      .simulate('click');
+    wrapper.update();
+    await wait();
+    expect(updateCase).toBeCalledWith(caseProps.caseData);
+    expect(fetchCaseUserActions).toBeCalledWith(caseProps.caseData.id);
+  });
+
+  it('should return null if error', () => {
+    (useGetCase as jest.Mock).mockImplementation(() => ({
+      ...defaultGetCase,
+      isError: true,
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseView
+            {...{
+              caseId: '1234',
+              userCanCrud: true,
+            }}
+          />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper).toEqual({});
+  });
+
+  it('should return spinner if loading', () => {
+    (useGetCase as jest.Mock).mockImplementation(() => ({
+      ...defaultGetCase,
+      isLoading: true,
+    }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseView
+            {...{
+              caseId: '1234',
+              userCanCrud: true,
+            }}
+          />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find('[data-test-subj="case-view-loading"]').exists()).toBeTruthy();
+  });
+
+  it('should return case view when data is there', () => {
+    (useGetCase as jest.Mock).mockImplementation(() => defaultGetCase);
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseView
+            {...{
+              caseId: '1234',
+              userCanCrud: true,
+            }}
+          />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find('[data-test-subj="case-view-title"]').exists()).toBeTruthy();
+  });
+
+  it('should refresh data on refresh', () => {
+    (useGetCase as jest.Mock).mockImplementation(() => defaultGetCase);
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <CaseView
+            {...{
+              caseId: '1234',
+              userCanCrud: true,
+            }}
+          />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find('[data-test-subj="case-refresh"]')
+      .first()
+      .simulate('click');
+    expect(fetchCaseUserActions).toBeCalledWith(caseProps.caseData.id);
+    expect(fetchCase).toBeCalled();
   });
 });
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx
index 947da51365d66..3cf0405f40637 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx
@@ -271,7 +271,11 @@ export const CaseComponent = React.memo<CaseProps>(
                           onChange={toggleStatusCase}
                         />
                       </EuiFlexItem>
-                      {hasDataToPush && <EuiFlexItem grow={false}>{pushButton}</EuiFlexItem>}
+                      {hasDataToPush && (
+                        <EuiFlexItem data-test-subj="has-data-to-push-button" grow={false}>
+                          {pushButton}
+                        </EuiFlexItem>
+                      )}
                     </EuiFlexGroup>
                   </>
                 )}
@@ -316,7 +320,7 @@ export const CaseView = React.memo(({ caseId, userCanCrud }: Props) => {
     return (
       <MyEuiFlexGroup justifyContent="center" alignItems="center">
         <EuiFlexItem grow={false}>
-          <EuiLoadingSpinner size="xl" />
+          <EuiLoadingSpinner data-test-subj="case-view-loading" size="xl" />
         </EuiFlexItem>
       </MyEuiFlexGroup>
     );
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.test.tsx
new file mode 100644
index 0000000000000..d480744fc932a
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.test.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { Create } from './';
+import { TestProviders } from '../../../../mock';
+import { getFormMock } from '../__mock__/form';
+import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
+
+import { useInsertTimeline } from '../../../../components/timeline/insert_timeline_popover/use_insert_timeline';
+import { usePostCase } from '../../../../containers/case/use_post_case';
+jest.mock('../../../../components/timeline/insert_timeline_popover/use_insert_timeline');
+jest.mock('../../../../containers/case/use_post_case');
+import { useForm } from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks';
+import { wait } from '../../../../lib/helpers';
+import { SiemPageName } from '../../../home/types';
+jest.mock(
+  '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'
+);
+
+export const useFormMock = useForm as jest.Mock;
+
+const useInsertTimelineMock = useInsertTimeline as jest.Mock;
+const usePostCaseMock = usePostCase as jest.Mock;
+
+const postCase = jest.fn();
+const handleCursorChange = jest.fn();
+const handleOnTimelineChange = jest.fn();
+
+const defaultInsertTimeline = {
+  cursorPosition: {
+    start: 0,
+    end: 0,
+  },
+  handleCursorChange,
+  handleOnTimelineChange,
+};
+const sampleData = {
+  description: 'what a great description',
+  tags: ['coke', 'pepsi'],
+  title: 'what a cool title',
+};
+const defaultPostCase = {
+  isLoading: false,
+  isError: false,
+  caseData: null,
+  postCase,
+};
+describe('Create case', () => {
+  const formHookMock = getFormMock(sampleData);
+
+  beforeEach(() => {
+    jest.resetAllMocks();
+    useInsertTimelineMock.mockImplementation(() => defaultInsertTimeline);
+    usePostCaseMock.mockImplementation(() => defaultPostCase);
+    useFormMock.mockImplementation(() => ({ form: formHookMock }));
+    jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation);
+  });
+
+  it('should post case on submit click', async () => {
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <Create />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="create-case-submit"]`)
+      .first()
+      .simulate('click');
+    await wait();
+    expect(postCase).toBeCalledWith(sampleData);
+  });
+
+  it('should redirect to all cases on cancel click', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <Create />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="create-case-cancel"]`)
+      .first()
+      .simulate('click');
+    expect(mockHistory.replace.mock.calls[0][0].pathname).toEqual(`/${SiemPageName.case}`);
+  });
+  it('should redirect to new case when caseData is there', () => {
+    const sampleId = '777777';
+    usePostCaseMock.mockImplementation(() => ({ ...defaultPostCase, caseData: { id: sampleId } }));
+    mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <Create />
+        </Router>
+      </TestProviders>
+    );
+    expect(mockHistory.replace.mock.calls[0][0].pathname).toEqual(
+      `/${SiemPageName.case}/${sampleId}`
+    );
+  });
+
+  it('should render spinner when loading', () => {
+    usePostCaseMock.mockImplementation(() => ({ ...defaultPostCase, isLoading: true }));
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <Create />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find(`[data-test-subj="create-case-loading-spinner"]`).exists()).toBeTruthy();
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx
index 740909db408ec..53b792bb9b5eb 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx
@@ -73,7 +73,7 @@ export const Create = React.memo(() => {
 
   const handleSetIsCancel = useCallback(() => {
     setIsCancel(true);
-  }, [isCancel]);
+  }, []);
 
   if (caseData != null && caseData.id) {
     return <Redirect to={`/${SiemPageName.case}/${caseData.id}`} />;
@@ -85,7 +85,7 @@ export const Create = React.memo(() => {
 
   return (
     <EuiPanel>
-      {isLoading && <MySpinner size="xl" />}
+      {isLoading && <MySpinner data-test-subj="create-case-loading-spinner" size="xl" />}
       <Form form={form}>
         <CommonUseField
           path="title"
@@ -107,7 +107,7 @@ export const Create = React.memo(() => {
               euiFieldProps: {
                 fullWidth: true,
                 placeholder: '',
-                isDisabled: isLoading,
+                disabled: isLoading,
               },
             }}
           />
@@ -151,6 +151,7 @@ export const Create = React.memo(() => {
           </EuiFlexItem>
           <EuiFlexItem grow={false}>
             <EuiButton
+              data-test-subj="create-case-submit"
               fill
               iconType="plusInCircle"
               isDisabled={isLoading}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.test.tsx
new file mode 100644
index 0000000000000..8ad2f8f8cb737
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.test.tsx
@@ -0,0 +1,138 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { TagList } from './';
+import { getFormMock } from '../__mock__/form';
+import { TestProviders } from '../../../../mock';
+import { wait } from '../../../../lib/helpers';
+import { useForm } from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks';
+import { act } from 'react-dom/test-utils';
+
+jest.mock(
+  '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'
+);
+const onSubmit = jest.fn();
+const defaultProps = {
+  disabled: false,
+  isLoading: false,
+  onSubmit,
+  tags: [],
+};
+
+describe('TagList ', () => {
+  const sampleTags = ['coke', 'pepsi'];
+  const formHookMock = getFormMock({ tags: sampleTags });
+  beforeEach(() => {
+    jest.resetAllMocks();
+    (useForm as jest.Mock).mockImplementation(() => ({ form: formHookMock }));
+  });
+  it('Renders no tags, and then edit', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <TagList {...defaultProps} />
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="no-tags"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+    wrapper
+      .find(`[data-test-subj="tag-list-edit-button"]`)
+      .last()
+      .simulate('click');
+    expect(
+      wrapper
+        .find(`[data-test-subj="no-tags"]`)
+        .last()
+        .exists()
+    ).toBeFalsy();
+    expect(
+      wrapper
+        .find(`[data-test-subj="edit-tags"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+  });
+  it('Edit tag on submit', async () => {
+    const wrapper = mount(
+      <TestProviders>
+        <TagList {...defaultProps} />
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="tag-list-edit-button"]`)
+      .last()
+      .simulate('click');
+    await act(async () => {
+      wrapper
+        .find(`[data-test-subj="edit-tags-submit"]`)
+        .last()
+        .simulate('click');
+      await wait();
+      expect(onSubmit).toBeCalledWith(sampleTags);
+    });
+  });
+  it('Cancels on cancel', async () => {
+    const props = {
+      ...defaultProps,
+      tags: ['pepsi'],
+    };
+    const wrapper = mount(
+      <TestProviders>
+        <TagList {...props} />
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="case-tag"]`)
+        .last()
+        .exists()
+    ).toBeTruthy();
+    wrapper
+      .find(`[data-test-subj="tag-list-edit-button"]`)
+      .last()
+      .simulate('click');
+    await act(async () => {
+      expect(
+        wrapper
+          .find(`[data-test-subj="case-tag"]`)
+          .last()
+          .exists()
+      ).toBeFalsy();
+      wrapper
+        .find(`[data-test-subj="edit-tags-cancel"]`)
+        .last()
+        .simulate('click');
+      await wait();
+      wrapper.update();
+      expect(
+        wrapper
+          .find(`[data-test-subj="case-tag"]`)
+          .last()
+          .exists()
+      ).toBeTruthy();
+    });
+  });
+  it('Renders disabled button', () => {
+    const props = { ...defaultProps, disabled: true };
+    const wrapper = mount(
+      <TestProviders>
+        <TagList {...props} />
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="tag-list-edit-button"]`)
+        .last()
+        .prop('disabled')
+    ).toBeTruthy();
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.tsx
index f7d890ca60b16..9bac000b93235 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/tag_list/index.tsx
@@ -61,10 +61,11 @@ export const TagList = React.memo(
           <EuiFlexItem grow={false}>
             <h4>{i18n.TAGS}</h4>
           </EuiFlexItem>
-          {isLoading && <EuiLoadingSpinner />}
+          {isLoading && <EuiLoadingSpinner data-test-subj="tag-list-loading" />}
           {!isLoading && (
-            <EuiFlexItem grow={false}>
+            <EuiFlexItem data-test-subj="tag-list-edit" grow={false}>
               <EuiButtonIcon
+                data-test-subj="tag-list-edit-button"
                 isDisabled={disabled}
                 aria-label={i18n.EDIT_TAGS_ARIA}
                 iconType={'pencil'}
@@ -74,17 +75,19 @@ export const TagList = React.memo(
           )}
         </EuiFlexGroup>
         <EuiHorizontalRule margin="xs" />
-        <MyFlexGroup gutterSize="xs">
-          {tags.length === 0 && !isEditTags && <p>{i18n.NO_TAGS}</p>}
+        <MyFlexGroup gutterSize="xs" data-test-subj="grr">
+          {tags.length === 0 && !isEditTags && <p data-test-subj="no-tags">{i18n.NO_TAGS}</p>}
           {tags.length > 0 &&
             !isEditTags &&
             tags.map((tag, key) => (
               <EuiFlexItem grow={false} key={`${tag}${key}`}>
-                <EuiBadge color="hollow">{tag}</EuiBadge>
+                <EuiBadge data-test-subj="case-tag" color="hollow">
+                  {tag}
+                </EuiBadge>
               </EuiFlexItem>
             ))}
           {isEditTags && (
-            <EuiFlexGroup direction="column">
+            <EuiFlexGroup data-test-subj="edit-tags" direction="column">
               <EuiFlexItem>
                 <Form form={form}>
                   <CommonUseField
@@ -105,6 +108,7 @@ export const TagList = React.memo(
                   <EuiFlexItem grow={false}>
                     <EuiButton
                       color="secondary"
+                      data-test-subj="edit-tags-submit"
                       fill
                       iconType="save"
                       onClick={onSubmitTags}
@@ -115,6 +119,7 @@ export const TagList = React.memo(
                   </EuiFlexItem>
                   <EuiFlexItem grow={false}>
                     <EuiButtonEmpty
+                      data-test-subj="edit-tags-cancel"
                       iconType="cross"
                       onClick={setIsEditTags.bind(null, false)}
                       size="s"
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx
new file mode 100644
index 0000000000000..77215e2318ded
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx
@@ -0,0 +1,192 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+/* eslint-disable react/display-name */
+import React from 'react';
+import { renderHook, act } from '@testing-library/react-hooks';
+import { usePushToService, ReturnUsePushToService, UsePushToService } from './';
+import { TestProviders } from '../../../../mock';
+import { usePostPushToService } from '../../../../containers/case/use_post_push_to_service';
+import { ClosureType } from '../../../../../../../../plugins/case/common/api/cases';
+import * as i18n from './translations';
+import { useGetActionLicense } from '../../../../containers/case/use_get_action_license';
+import { getKibanaConfigError, getLicenseError } from './helpers';
+import * as api from '../../../../containers/case/configure/api';
+jest.mock('../../../../containers/case/use_get_action_license');
+jest.mock('../../../../containers/case/use_post_push_to_service');
+jest.mock('../../../../containers/case/configure/api');
+
+describe('usePushToService', () => {
+  const caseId = '12345';
+  const updateCase = jest.fn();
+  const postPushToService = jest.fn();
+  const mockPostPush = {
+    isLoading: false,
+    postPushToService,
+  };
+  const closureType: ClosureType = 'close-by-user';
+  const mockConnector = {
+    connectorId: 'c00l',
+    connectorName: 'name',
+  };
+  const mockCaseConfigure = {
+    ...mockConnector,
+    createdAt: 'string',
+    createdBy: {},
+    closureType,
+    updatedAt: 'string',
+    updatedBy: {},
+    version: 'string',
+  };
+  const getConfigureMock = jest.spyOn(api, 'getCaseConfigure');
+  const actionLicense = {
+    id: '.servicenow',
+    name: 'ServiceNow',
+    minimumLicenseRequired: 'platinum',
+    enabled: true,
+    enabledInConfig: true,
+    enabledInLicense: true,
+  };
+  beforeEach(() => {
+    jest.resetAllMocks();
+    (usePostPushToService as jest.Mock).mockImplementation(() => mockPostPush);
+    (useGetActionLicense as jest.Mock).mockImplementation(() => ({
+      isLoading: false,
+      actionLicense,
+    }));
+    getConfigureMock.mockImplementation(() => Promise.resolve(mockCaseConfigure));
+  });
+  it('push case button posts the push with correct args', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<UsePushToService, ReturnUsePushToService>(
+        () =>
+          usePushToService({
+            caseId,
+            caseStatus: 'open',
+            isNew: false,
+            updateCase,
+            userCanCrud: true,
+          }),
+        {
+          wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
+        }
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      expect(getConfigureMock).toBeCalled();
+      result.current.pushButton.props.children.props.onClick();
+      expect(postPushToService).toBeCalledWith({ ...mockConnector, caseId, updateCase });
+      expect(result.current.pushCallouts).toBeNull();
+    });
+  });
+  it('Displays message when user does not have premium license', async () => {
+    (useGetActionLicense as jest.Mock).mockImplementation(() => ({
+      isLoading: false,
+      actionLicense: {
+        ...actionLicense,
+        enabledInLicense: false,
+      },
+    }));
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<UsePushToService, ReturnUsePushToService>(
+        () =>
+          usePushToService({
+            caseId,
+            caseStatus: 'open',
+            isNew: false,
+            updateCase,
+            userCanCrud: true,
+          }),
+        {
+          wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
+        }
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      const errorsMsg = result.current.pushCallouts?.props.messages;
+      expect(errorsMsg).toHaveLength(1);
+      expect(errorsMsg[0].title).toEqual(getLicenseError().title);
+    });
+  });
+  it('Displays message when user does not have case enabled in config', async () => {
+    (useGetActionLicense as jest.Mock).mockImplementation(() => ({
+      isLoading: false,
+      actionLicense: {
+        ...actionLicense,
+        enabledInConfig: false,
+      },
+    }));
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<UsePushToService, ReturnUsePushToService>(
+        () =>
+          usePushToService({
+            caseId,
+            caseStatus: 'open',
+            isNew: false,
+            updateCase,
+            userCanCrud: true,
+          }),
+        {
+          wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
+        }
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      const errorsMsg = result.current.pushCallouts?.props.messages;
+      expect(errorsMsg).toHaveLength(1);
+      expect(errorsMsg[0].title).toEqual(getKibanaConfigError().title);
+    });
+  });
+  it('Displays message when user does not have a connector configured', async () => {
+    getConfigureMock.mockImplementation(() =>
+      Promise.resolve({
+        ...mockCaseConfigure,
+        connectorId: 'none',
+      })
+    );
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<UsePushToService, ReturnUsePushToService>(
+        () =>
+          usePushToService({
+            caseId,
+            caseStatus: 'open',
+            isNew: false,
+            updateCase,
+            userCanCrud: true,
+          }),
+        {
+          wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
+        }
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      const errorsMsg = result.current.pushCallouts?.props.messages;
+      expect(errorsMsg).toHaveLength(1);
+      expect(errorsMsg[0].title).toEqual(i18n.PUSH_DISABLE_BY_NO_CASE_CONFIG_TITLE);
+    });
+  });
+  it('Displays message when case is closed', async () => {
+    await act(async () => {
+      const { result, waitForNextUpdate } = renderHook<UsePushToService, ReturnUsePushToService>(
+        () =>
+          usePushToService({
+            caseId,
+            caseStatus: 'closed',
+            isNew: false,
+            updateCase,
+            userCanCrud: true,
+          }),
+        {
+          wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
+        }
+      );
+      await waitForNextUpdate();
+      await waitForNextUpdate();
+      const errorsMsg = result.current.pushCallouts?.props.messages;
+      expect(errorsMsg).toHaveLength(1);
+      expect(errorsMsg[0].title).toEqual(i18n.PUSH_DISABLE_BECAUSE_CASE_CLOSED_TITLE);
+    });
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx
index 4f370ec978906..5092cba6872e3 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx
@@ -19,7 +19,7 @@ import { CaseCallOut } from '../callout';
 import { getLicenseError, getKibanaConfigError } from './helpers';
 import * as i18n from './translations';
 
-interface UsePushToService {
+export interface UsePushToService {
   caseId: string;
   caseStatus: string;
   isNew: boolean;
@@ -32,7 +32,7 @@ interface Connector {
   connectorName: string;
 }
 
-interface ReturnUsePushToService {
+export interface ReturnUsePushToService {
   pushButton: JSX.Element;
   pushCallouts: JSX.Element | null;
 }
@@ -122,6 +122,7 @@ export const usePushToService = ({
   const pushToServiceButton = useMemo(
     () => (
       <EuiButton
+        data-test-subj="push-to-service-now"
         fill
         iconType="importAction"
         onClick={handlePushToService}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.test.tsx
new file mode 100644
index 0000000000000..5c342538f0feb
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.test.tsx
@@ -0,0 +1,143 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { getUserAction } from '../__mock__/case_data';
+import { getLabelTitle } from './helpers';
+import * as i18n from '../case_view/translations';
+import { mount } from 'enzyme';
+
+describe('User action tree helpers', () => {
+  it('label title generated for update tags', () => {
+    const action = getUserAction(['title'], 'update');
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'tags',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    const wrapper = mount(<>{result}</>);
+    expect(
+      wrapper
+        .find(`[data-test-subj="ua-tags-label"]`)
+        .first()
+        .text()
+    ).toEqual(` ${i18n.TAGS.toLowerCase()}`);
+
+    expect(
+      wrapper
+        .find(`[data-test-subj="ua-tag"]`)
+        .first()
+        .text()
+    ).toEqual(action.newValue);
+  });
+  it('label title generated for update title', () => {
+    const action = getUserAction(['title'], 'update');
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'title',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    expect(result).toEqual(
+      `${i18n.CHANGED_FIELD.toLowerCase()} ${i18n.CASE_NAME.toLowerCase()}  ${i18n.TO} "${
+        action.newValue
+      }"`
+    );
+  });
+  it('label title generated for update description', () => {
+    const action = getUserAction(['description'], 'update');
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'description',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    expect(result).toEqual(`${i18n.EDITED_FIELD} ${i18n.DESCRIPTION.toLowerCase()}`);
+  });
+  it('label title generated for update status to open', () => {
+    const action = { ...getUserAction(['status'], 'update'), newValue: 'open' };
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'status',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    expect(result).toEqual(`${i18n.REOPENED_CASE.toLowerCase()} ${i18n.CASE}`);
+  });
+  it('label title generated for update status to closed', () => {
+    const action = { ...getUserAction(['status'], 'update'), newValue: 'closed' };
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'status',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    expect(result).toEqual(`${i18n.CLOSED_CASE.toLowerCase()} ${i18n.CASE}`);
+  });
+  it('label title generated for update comment', () => {
+    const action = getUserAction(['comment'], 'update');
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'comment',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    expect(result).toEqual(`${i18n.EDITED_FIELD} ${i18n.COMMENT.toLowerCase()}`);
+  });
+  it('label title generated for pushed incident', () => {
+    const action = getUserAction(['pushed'], 'push-to-service');
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'pushed',
+      firstIndexPushToService: 0,
+      index: 0,
+    });
+
+    const wrapper = mount(<>{result}</>);
+    expect(
+      wrapper
+        .find(`[data-test-subj="pushed-label"]`)
+        .first()
+        .text()
+    ).toEqual(i18n.PUSHED_NEW_INCIDENT);
+    expect(
+      wrapper
+        .find(`[data-test-subj="pushed-value"]`)
+        .first()
+        .prop('href')
+    ).toEqual(JSON.parse(action.newValue).external_url);
+  });
+  it('label title generated for needs update incident', () => {
+    const action = getUserAction(['pushed'], 'push-to-service');
+    const result: string | JSX.Element = getLabelTitle({
+      action,
+      field: 'pushed',
+      firstIndexPushToService: 0,
+      index: 1,
+    });
+
+    const wrapper = mount(<>{result}</>);
+    expect(
+      wrapper
+        .find(`[data-test-subj="pushed-label"]`)
+        .first()
+        .text()
+    ).toEqual(i18n.UPDATE_INCIDENT);
+    expect(
+      wrapper
+        .find(`[data-test-subj="pushed-value"]`)
+        .first()
+        .prop('href')
+    ).toEqual(JSON.parse(action.newValue).external_url);
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.tsx
index 008f4d7048f56..d6016e540bdc0 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/helpers.tsx
@@ -41,14 +41,16 @@ export const getLabelTitle = ({ action, field, firstIndexPushToService, index }:
 
 const getTagsLabelTitle = (action: CaseUserActions) => (
   <EuiFlexGroup alignItems="baseline" gutterSize="xs" component="span">
-    <EuiFlexItem>
+    <EuiFlexItem data-test-subj="ua-tags-label">
       {action.action === 'add' && i18n.ADDED_FIELD}
       {action.action === 'delete' && i18n.REMOVED_FIELD} {i18n.TAGS.toLowerCase()}
     </EuiFlexItem>
     {action.newValue != null &&
       action.newValue.split(',').map(tag => (
         <EuiFlexItem grow={false} key={tag}>
-          <EuiBadge color="default">{tag}</EuiBadge>
+          <EuiBadge data-test-subj={`ua-tag`} color="default">
+            {tag}
+          </EuiBadge>
         </EuiFlexItem>
       ))}
   </EuiFlexGroup>
@@ -61,12 +63,12 @@ const getPushedServiceLabelTitle = (
 ) => {
   const pushedVal = JSON.parse(action.newValue ?? '') as CaseFullExternalService;
   return (
-    <EuiFlexGroup alignItems="baseline" gutterSize="xs">
-      <EuiFlexItem>
+    <EuiFlexGroup alignItems="baseline" gutterSize="xs" data-test-subj="pushed-service-label-title">
+      <EuiFlexItem data-test-subj="pushed-label">
         {firstIndexPushToService === index ? i18n.PUSHED_NEW_INCIDENT : i18n.UPDATE_INCIDENT}
       </EuiFlexItem>
       <EuiFlexItem grow={false}>
-        <EuiLink href={pushedVal?.external_url} target="_blank">
+        <EuiLink data-test-subj="pushed-value" href={pushedVal?.external_url} target="_blank">
           {pushedVal?.connector_name} {pushedVal?.external_title}
         </EuiLink>
       </EuiFlexItem>
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx
new file mode 100644
index 0000000000000..0d8cd729b4a1d
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx
@@ -0,0 +1,331 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
+import { getFormMock } from '../__mock__/form';
+import { useUpdateComment } from '../../../../containers/case/use_update_comment';
+import { basicCase, getUserAction } from '../__mock__/case_data';
+import { UserActionTree } from './';
+import { TestProviders } from '../../../../mock';
+import { useFormMock } from '../create/index.test';
+import { wait } from '../../../../lib/helpers';
+import { act } from 'react-dom/test-utils';
+jest.mock(
+  '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'
+);
+
+const fetchUserActions = jest.fn();
+const onUpdateField = jest.fn();
+const updateCase = jest.fn();
+const defaultProps = {
+  data: basicCase,
+  caseUserActions: [],
+  firstIndexPushToService: -1,
+  isLoadingDescription: false,
+  isLoadingUserActions: false,
+  lastIndexPushToService: -1,
+  userCanCrud: true,
+  fetchUserActions,
+  onUpdateField,
+  updateCase,
+};
+const useUpdateCommentMock = useUpdateComment as jest.Mock;
+jest.mock('../../../../containers/case/use_update_comment');
+
+const patchComment = jest.fn();
+describe('UserActionTree ', () => {
+  const sampleData = {
+    content: 'what a great comment update',
+  };
+  beforeEach(() => {
+    jest.clearAllMocks();
+    jest.resetAllMocks();
+    useUpdateCommentMock.mockImplementation(() => ({
+      isLoadingIds: [],
+      patchComment,
+    }));
+    const formHookMock = getFormMock(sampleData);
+    useFormMock.mockImplementation(() => ({ form: formHookMock }));
+    jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation);
+  });
+
+  it('Loading spinner when user actions loading and displays fullName/username', () => {
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...{ ...defaultProps, isLoadingUserActions: true }} />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find(`[data-test-subj="user-actions-loading"]`).exists()).toBeTruthy();
+
+    expect(
+      wrapper
+        .find(`[data-test-subj="user-action-avatar"]`)
+        .first()
+        .prop('name')
+    ).toEqual(defaultProps.data.createdBy.fullName);
+    expect(
+      wrapper
+        .find(`[data-test-subj="user-action-title"] strong`)
+        .first()
+        .text()
+    ).toEqual(defaultProps.data.createdBy.username);
+  });
+  it('Renders service now update line with top and bottom when push is required', () => {
+    const ourActions = [
+      getUserAction(['comment'], 'push-to-service'),
+      getUserAction(['comment'], 'update'),
+    ];
+    const props = {
+      ...defaultProps,
+      caseUserActions: ourActions,
+      lastIndexPushToService: 0,
+    };
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find(`[data-test-subj="show-top-footer"]`).exists()).toBeTruthy();
+    expect(wrapper.find(`[data-test-subj="show-bottom-footer"]`).exists()).toBeTruthy();
+  });
+  it('Renders service now update line with top only when push is up to date', () => {
+    const ourActions = [getUserAction(['comment'], 'push-to-service')];
+    const props = {
+      ...defaultProps,
+      caseUserActions: ourActions,
+      lastIndexPushToService: 0,
+    };
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    expect(wrapper.find(`[data-test-subj="show-top-footer"]`).exists()).toBeTruthy();
+    expect(wrapper.find(`[data-test-subj="show-bottom-footer"]`).exists()).toBeFalsy();
+  });
+
+  it('Outlines comment when update move to link is clicked', () => {
+    const ourActions = [getUserAction(['comment'], 'create'), getUserAction(['comment'], 'update')];
+    const props = {
+      ...defaultProps,
+      caseUserActions: ourActions,
+    };
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="comment-create-action"]`)
+        .first()
+        .prop('idToOutline')
+    ).toEqual('');
+    wrapper
+      .find(`[data-test-subj="comment-update-action"] [data-test-subj="move-to-link"]`)
+      .first()
+      .simulate('click');
+    expect(
+      wrapper
+        .find(`[data-test-subj="comment-create-action"]`)
+        .first()
+        .prop('idToOutline')
+    ).toEqual(ourActions[0].commentId);
+  });
+
+  it('Switches to markdown when edit is clicked and back to panel when canceled', () => {
+    const ourActions = [getUserAction(['comment'], 'create')];
+    const props = {
+      ...defaultProps,
+      caseUserActions: ourActions,
+    };
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(
+          `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+        )
+        .exists()
+    ).toEqual(false);
+    wrapper
+      .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-ellipses"]`)
+      .first()
+      .simulate('click');
+    wrapper
+      .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-pencil"]`)
+      .first()
+      .simulate('click');
+    expect(
+      wrapper
+        .find(
+          `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+        )
+        .exists()
+    ).toEqual(true);
+    wrapper
+      .find(
+        `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-cancel-markdown"]`
+      )
+      .first()
+      .simulate('click');
+    expect(
+      wrapper
+        .find(
+          `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+        )
+        .exists()
+    ).toEqual(false);
+  });
+
+  it('calls update comment when comment markdown is saved', async () => {
+    const ourActions = [getUserAction(['comment'], 'create')];
+    const props = {
+      ...defaultProps,
+      caseUserActions: ourActions,
+    };
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-ellipses"]`)
+      .first()
+      .simulate('click');
+    wrapper
+      .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-pencil"]`)
+      .first()
+      .simulate('click');
+    wrapper
+      .find(
+        `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-save-markdown"]`
+      )
+      .first()
+      .simulate('click');
+    await act(async () => {
+      await wait();
+      wrapper.update();
+      expect(
+        wrapper
+          .find(
+            `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+          )
+          .exists()
+      ).toEqual(false);
+      expect(patchComment).toBeCalledWith({
+        commentUpdate: sampleData.content,
+        caseId: props.data.id,
+        commentId: props.data.comments[0].id,
+        fetchUserActions,
+        updateCase,
+        version: props.data.comments[0].version,
+      });
+    });
+  });
+
+  it('calls update description when description markdown is saved', async () => {
+    const props = defaultProps;
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-ellipses"]`)
+      .first()
+      .simulate('click');
+    wrapper
+      .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-pencil"]`)
+      .first()
+      .simulate('click');
+    wrapper
+      .find(
+        `[data-test-subj="user-action-description"] [data-test-subj="user-action-save-markdown"]`
+      )
+      .first()
+      .simulate('click');
+    await act(async () => {
+      await wait();
+      expect(
+        wrapper
+          .find(
+            `[data-test-subj="user-action-${props.data.id}"] [data-test-subj="user-action-markdown-form"]`
+          )
+          .exists()
+      ).toEqual(false);
+      expect(onUpdateField).toBeCalledWith('description', sampleData.content);
+    });
+  });
+
+  it('quotes', async () => {
+    const commentData = {
+      comment: '',
+    };
+    const formHookMock = getFormMock(commentData);
+    const setFieldValue = jest.fn();
+    useFormMock.mockImplementation(() => ({ form: { ...formHookMock, setFieldValue } }));
+    const props = defaultProps;
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-ellipses"]`)
+      .first()
+      .simulate('click');
+    wrapper
+      .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-quote"]`)
+      .first()
+      .simulate('click');
+    expect(setFieldValue).toBeCalledWith('comment', `> ${props.data.description} \n`);
+  });
+  it('Outlines comment when url param is provided', () => {
+    const commentId = 'neat-comment-id';
+    const ourActions = [getUserAction(['comment'], 'create')];
+    const props = {
+      ...defaultProps,
+      caseUserActions: ourActions,
+    };
+    jest.spyOn(routeData, 'useParams').mockReturnValue({ commentId });
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTree {...props} />
+        </Router>
+      </TestProviders>
+    );
+    expect(
+      wrapper
+        .find(`[data-test-subj="comment-create-action"]`)
+        .first()
+        .prop('idToOutline')
+    ).toEqual(commentId);
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.tsx
index 0892d5dcb3ee7..f8f3f0651fa3c 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/index.tsx
@@ -60,7 +60,6 @@ export const UserActionTree = React.memo(
     const currentUser = useCurrentUser();
     const [manageMarkdownEditIds, setManangeMardownEditIds] = useState<string[]>([]);
     const [insertQuote, setInsertQuote] = useState<string | null>(null);
-
     const handleManageMarkdownEditId = useCallback(
       (id: string) => {
         if (!manageMarkdownEditIds.includes(id)) {
@@ -74,7 +73,6 @@ export const UserActionTree = React.memo(
 
     const handleSaveComment = useCallback(
       ({ id, version }: { id: string; version: string }, content: string) => {
-        handleManageMarkdownEditId(id);
         patchComment({
           caseId: caseData.id,
           commentId: id,
@@ -135,7 +133,6 @@ export const UserActionTree = React.memo(
           content={caseData.description}
           isEditable={manageMarkdownEditIds.includes(DESCRIPTION_ID)}
           onSaveContent={(content: string) => {
-            handleManageMarkdownEditId(DESCRIPTION_ID);
             onUpdateField(DESCRIPTION_ID, content);
           }}
           onChangeEditable={handleManageMarkdownEditId}
@@ -166,11 +163,11 @@ export const UserActionTree = React.memo(
         }
       }
     }, [commentId, initLoading, isLoadingUserActions, isLoadingIds]);
-
     return (
       <>
         <UserActionItem
           createdAt={caseData.createdAt}
+          data-test-subj="description-action"
           disabled={!userCanCrud}
           id={DESCRIPTION_ID}
           isEditable={manageMarkdownEditIds.includes(DESCRIPTION_ID)}
@@ -193,6 +190,7 @@ export const UserActionTree = React.memo(
                 <UserActionItem
                   key={action.actionId}
                   createdAt={comment.createdAt}
+                  data-test-subj={`comment-create-action`}
                   disabled={!userCanCrud}
                   id={comment.id}
                   idToOutline={selectedOutlineCommentId}
@@ -236,6 +234,7 @@ export const UserActionTree = React.memo(
               <UserActionItem
                 key={action.actionId}
                 createdAt={action.actionAt}
+                data-test-subj={`${action.actionField[0]}-${action.action}-action`}
                 disabled={!userCanCrud}
                 id={action.actionId}
                 isEditable={false}
@@ -263,11 +262,12 @@ export const UserActionTree = React.memo(
         {(isLoadingUserActions || isLoadingIds.includes(NEW_ID)) && (
           <MyEuiFlexGroup justifyContent="center" alignItems="center">
             <EuiFlexItem grow={false}>
-              <EuiLoadingSpinner size="l" />
+              <EuiLoadingSpinner data-test-subj="user-actions-loading" size="l" />
             </EuiFlexItem>
           </MyEuiFlexGroup>
         )}
         <UserActionItem
+          data-test-subj={`add-comment`}
           createdAt={new Date().toISOString()}
           disabled={!userCanCrud}
           id={NEW_ID}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_item.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_item.tsx
index bcb4edd6129a6..0acd0623f9413 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_item.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_item.tsx
@@ -21,6 +21,7 @@ import * as i18n from './translations';
 
 interface UserActionItemProps {
   createdAt: string;
+  'data-test-subj'?: string;
   disabled: boolean;
   id: string;
   isEditable: boolean;
@@ -112,6 +113,7 @@ const PushedInfoContainer = styled.div`
 export const UserActionItem = ({
   createdAt,
   disabled,
+  'data-test-subj': dataTestSubj,
   id,
   idToOutline,
   isEditable,
@@ -130,7 +132,7 @@ export const UserActionItem = ({
   username,
   updatedAt,
 }: UserActionItemProps) => (
-  <UserActionItemContainer gutterSize={'none'} direction="column">
+  <UserActionItemContainer data-test-subj={dataTestSubj} gutterSize={'none'} direction="column">
     <EuiFlexItem>
       <EuiFlexGroup gutterSize={'none'}>
         <EuiFlexItem data-test-subj={`user-action-${id}-avatar`} grow={false}>
@@ -145,24 +147,25 @@ export const UserActionItem = ({
           {!isEditable && (
             <MyEuiPanel
               className="userAction__panel"
+              data-test-subj={`user-action-panel`}
               paddingSize="none"
               showoutline={id === idToOutline ? 'true' : 'false'}
             >
               <UserActionTitle
                 createdAt={createdAt}
                 disabled={disabled}
+                fullName={fullName}
                 id={id}
                 isLoading={isLoading}
                 labelEditAction={labelEditAction}
                 labelQuoteAction={labelQuoteAction}
                 labelTitle={labelTitle ?? <></>}
                 linkId={linkId}
-                fullName={fullName}
-                username={username}
-                updatedAt={updatedAt}
                 onEdit={onEdit}
                 onQuote={onQuote}
                 outlineComment={outlineComment}
+                updatedAt={updatedAt}
+                username={username}
               />
               {markdown}
             </MyEuiPanel>
@@ -171,7 +174,7 @@ export const UserActionItem = ({
       </EuiFlexGroup>
     </EuiFlexItem>
     {showTopFooter && (
-      <PushedContainer>
+      <PushedContainer data-test-subj="show-top-footer">
         <PushedInfoContainer>
           <EuiText size="xs" color="subdued">
             {i18n.ALREADY_PUSHED_TO_SERVICE}
@@ -179,7 +182,7 @@ export const UserActionItem = ({
         </PushedInfoContainer>
         <EuiHorizontalRule />
         {showBottomFooter && (
-          <PushedInfoContainer>
+          <PushedInfoContainer data-test-subj="show-bottom-footer">
             <EuiText size="xs" color="subdued">
               {i18n.REQUIRED_UPDATE_TO_SERVICE}
             </EuiText>
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_markdown.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_markdown.tsx
index e8503bf43375c..827fe2df120ab 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_markdown.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_markdown.tsx
@@ -62,12 +62,24 @@ export const UserActionMarkdown = ({
       return (
         <EuiFlexGroup gutterSize="s" alignItems="center">
           <EuiFlexItem grow={false}>
-            <EuiButtonEmpty size="s" onClick={cancelAction} iconType="cross">
+            <EuiButtonEmpty
+              data-test-subj="user-action-cancel-markdown"
+              size="s"
+              onClick={cancelAction}
+              iconType="cross"
+            >
               {i18n.CANCEL}
             </EuiButtonEmpty>
           </EuiFlexItem>
           <EuiFlexItem grow={false}>
-            <EuiButton color="secondary" fill iconType="save" onClick={saveAction} size="s">
+            <EuiButton
+              data-test-subj="user-action-save-markdown"
+              color="secondary"
+              fill
+              iconType="save"
+              onClick={saveAction}
+              size="s"
+            >
               {i18n.SAVE}
             </EuiButton>
           </EuiFlexItem>
@@ -77,7 +89,7 @@ export const UserActionMarkdown = ({
     [handleCancelAction, handleSaveAction]
   );
   return isEditable ? (
-    <Form form={form}>
+    <Form form={form} data-test-subj="user-action-markdown-form">
       <UseField
         path="content"
         component={MarkdownEditorForm}
@@ -99,7 +111,7 @@ export const UserActionMarkdown = ({
     </Form>
   ) : (
     <ContentWrapper>
-      <Markdown raw={content} data-test-subj="case-view-description" />
+      <Markdown raw={content} data-test-subj="user-action-markdown" />
     </ContentWrapper>
   );
 };
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.test.tsx
new file mode 100644
index 0000000000000..e2189367068ca
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.test.tsx
@@ -0,0 +1,57 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+import copy from 'copy-to-clipboard';
+import { Router, routeData, mockHistory } from '../__mock__/router';
+import { caseUserActions as basicUserActions } from '../__mock__/case_data';
+import { UserActionTitle } from './user_action_title';
+import { TestProviders } from '../../../../mock';
+
+const outlineComment = jest.fn();
+const onEdit = jest.fn();
+const onQuote = jest.fn();
+
+jest.mock('copy-to-clipboard');
+const defaultProps = {
+  createdAt: basicUserActions[0].actionAt,
+  disabled: false,
+  fullName: basicUserActions[0].actionBy.fullName,
+  id: basicUserActions[0].actionId,
+  isLoading: false,
+  labelEditAction: 'labelEditAction',
+  labelQuoteAction: 'labelQuoteAction',
+  labelTitle: <>{'cool'}</>,
+  linkId: basicUserActions[0].commentId,
+  onEdit,
+  onQuote,
+  outlineComment,
+  updatedAt: basicUserActions[0].actionAt,
+  username: basicUserActions[0].actionBy.username,
+};
+
+describe('UserActionTitle ', () => {
+  beforeEach(() => {
+    jest.resetAllMocks();
+    jest.spyOn(routeData, 'useParams').mockReturnValue({ commentId: '123' });
+  });
+
+  it('Calls copy when copy link is clicked', async () => {
+    const wrapper = mount(
+      <TestProviders>
+        <Router history={mockHistory}>
+          <UserActionTitle {...defaultProps} />
+        </Router>
+      </TestProviders>
+    );
+    wrapper
+      .find(`[data-test-subj="copy-link"]`)
+      .first()
+      .simulate('click');
+    expect(copy).toBeCalledTimes(1);
+  });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.tsx
index 9ccf921c87602..a1edbab7e1fa2 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_action_tree/user_action_title.tsx
@@ -52,18 +52,18 @@ interface UserActionTitleProps {
 export const UserActionTitle = ({
   createdAt,
   disabled,
+  fullName,
   id,
   isLoading,
   labelEditAction,
   labelQuoteAction,
   labelTitle,
   linkId,
-  fullName,
-  username,
-  updatedAt,
   onEdit,
   onQuote,
   outlineComment,
+  updatedAt,
+  username,
 }: UserActionTitleProps) => {
   const { detailName: caseId } = useParams();
   const urlSearch = useGetUrlSearch(navTabs.case);
@@ -94,10 +94,7 @@ export const UserActionTitle = ({
 
   const handleAnchorLink = useCallback(() => {
     copy(
-      `${window.location.origin}${window.location.pathname}#${SiemPageName.case}/${caseId}/${id}${urlSearch}`,
-      {
-        debug: true,
-      }
+      `${window.location.origin}${window.location.pathname}#${SiemPageName.case}/${caseId}/${id}${urlSearch}`
     );
   }, [caseId, id, urlSearch]);
 
@@ -106,7 +103,6 @@ export const UserActionTitle = ({
       outlineComment(linkId);
     }
   }, [linkId, outlineComment]);
-
   return (
     <EuiText size="s" className="userAction__title" data-test-subj={`user-action-title`}>
       <EuiFlexGroup
@@ -155,6 +151,7 @@ export const UserActionTitle = ({
                 <EuiToolTip position="top" content={<p>{i18n.MOVE_TO_ORIGINAL_COMMENT}</p>}>
                   <EuiButtonIcon
                     aria-label={i18n.MOVE_TO_ORIGINAL_COMMENT}
+                    data-test-subj={`move-to-link`}
                     onClick={handleMoveToLink}
                     iconType="arrowUp"
                   />
@@ -165,6 +162,7 @@ export const UserActionTitle = ({
               <EuiToolTip position="top" content={<p>{i18n.COPY_REFERENCE_LINK}</p>}>
                 <EuiButtonIcon
                   aria-label={i18n.COPY_REFERENCE_LINK}
+                  data-test-subj={`copy-link`}
                   onClick={handleAnchorLink}
                   iconType="link"
                   id={`${id}-permLink`}
@@ -173,7 +171,7 @@ export const UserActionTitle = ({
             </EuiFlexItem>
             {propertyActions.length > 0 && (
               <EuiFlexItem grow={false}>
-                {isLoading && <MySpinner />}
+                {isLoading && <MySpinner data-test-subj="user-action-title-loading" />}
                 {!isLoading && <PropertyActions propertyActions={propertyActions} />}
               </EuiFlexItem>
             )}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/translations.ts b/x-pack/legacy/plugins/siem/public/pages/case/translations.ts
index 0d1e6d1435ca3..097b8220156e2 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/case/translations.ts
@@ -131,6 +131,10 @@ export const TAGS = i18n.translate('xpack.siem.case.caseView.tags', {
   defaultMessage: 'Tags',
 });
 
+export const ACTIONS = i18n.translate('xpack.siem.case.allCases.actions', {
+  defaultMessage: 'Actions',
+});
+
 export const NO_TAGS_AVAILABLE = i18n.translate('xpack.siem.case.allCases.noTagsAvailable', {
   defaultMessage: 'No tags available',
 });
diff --git a/x-pack/plugins/case/server/scripts/generate_case_and_comment_data.sh b/x-pack/plugins/case/server/scripts/generate_case_and_comment_data.sh
index 9b6f472d798e0..7ec7dc5a70e92 100755
--- a/x-pack/plugins/case/server/scripts/generate_case_and_comment_data.sh
+++ b/x-pack/plugins/case/server/scripts/generate_case_and_comment_data.sh
@@ -22,9 +22,9 @@ POSTED_COMMENT="$(curl -s -k \
   -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
   -X POST "${KIBANA_URL}${SPACE_URL}/api/cases/$CASE_ID/comments" \
   -d @${COMMENT} \
-  | jq '{ commentId: .id, commentVersion: .version }'
-)"
+  | jq '{ commentId: .comments[0].id, commentVersion: .comments[0].version }' \
+-j)"
 POSTED_CASE=$(./get_case.sh $CASE_ID | jq '{ caseId: .id, caseVersion: .version }' -j)
 
 echo ${POSTED_COMMENT} ${POSTED_CASE} \
-  | jq -s add;
\ No newline at end of file
+| jq -s add;
diff --git a/x-pack/plugins/case/server/scripts/generate_case_data.sh b/x-pack/plugins/case/server/scripts/generate_case_data.sh
index f8f6142a5d733..d3a4d3833ad2e 100755
--- a/x-pack/plugins/case/server/scripts/generate_case_data.sh
+++ b/x-pack/plugins/case/server/scripts/generate_case_data.sh
@@ -11,6 +11,6 @@
 # ./generate_case_data.sh
 
 set -e
-./check_env_variables.sh
-./post_case.sh | jq '{ id: .id, version: .version }' -j;
+  ./check_env_variables.sh
+  ./post_case.sh | jq '{ id: .id, version: .version }';
 

From d5d610f168895ba373dec0db3d0caa64bf6a4b47 Mon Sep 17 00:00:00 2001
From: Robert Austin <robert.austin@elastic.co>
Date: Fri, 10 Apr 2020 12:19:29 -0400
Subject: [PATCH 54/78] Endpoint: Remove unused `lib` module (#63248)

---
 .../public/applications/endpoint/lib/index.ts |   7 -
 .../applications/endpoint/lib/saga.test.ts    | 114 -------------
 .../public/applications/endpoint/lib/saga.ts  | 159 ------------------
 3 files changed, 280 deletions(-)
 delete mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/lib/index.ts
 delete mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.test.ts
 delete mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.ts

diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/lib/index.ts b/x-pack/plugins/endpoint/public/applications/endpoint/lib/index.ts
deleted file mode 100644
index ba2e1ce8f9fe6..0000000000000
--- a/x-pack/plugins/endpoint/public/applications/endpoint/lib/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export * from './saga';
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.test.ts
deleted file mode 100644
index 7c06681184085..0000000000000
--- a/x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.test.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { createSagaMiddleware, SagaContext, SagaMiddleware } from './index';
-import { applyMiddleware, createStore, Reducer, Store } from 'redux';
-
-describe('saga', () => {
-  const INCREMENT_COUNTER = 'INCREMENT';
-  const DELAYED_INCREMENT_COUNTER = 'DELAYED INCREMENT COUNTER';
-  const STOP_SAGA_PROCESSING = 'BREAK ASYNC ITERATOR';
-
-  const sleep = (ms = 100) => new Promise(resolve => setTimeout(resolve, ms));
-  let store: Store;
-  let reducerA: Reducer;
-  let sideAffect: (a: unknown, s: unknown) => void;
-  let sagaExe: (sagaContext: SagaContext) => Promise<void>;
-  let sagaExeReduxMiddleware: SagaMiddleware;
-
-  beforeEach(() => {
-    reducerA = jest.fn((prevState = { count: 0 }, { type }) => {
-      switch (type) {
-        case INCREMENT_COUNTER:
-          return { ...prevState, count: prevState.count + 1 };
-        default:
-          return prevState;
-      }
-    });
-
-    sideAffect = jest.fn();
-
-    sagaExe = jest.fn(async ({ actionsAndState, dispatch }: SagaContext) => {
-      for await (const { action, state } of actionsAndState()) {
-        expect(action).toBeDefined();
-        expect(state).toBeDefined();
-
-        if (action.type === STOP_SAGA_PROCESSING) {
-          break;
-        }
-
-        sideAffect(action, state);
-
-        if (action.type === DELAYED_INCREMENT_COUNTER) {
-          await sleep(1);
-          dispatch({
-            type: INCREMENT_COUNTER,
-          });
-        }
-      }
-    });
-
-    sagaExeReduxMiddleware = createSagaMiddleware(sagaExe);
-    store = createStore(reducerA, applyMiddleware(sagaExeReduxMiddleware));
-  });
-
-  afterEach(() => {
-    sagaExeReduxMiddleware.stop();
-  });
-
-  test('it does nothing if saga is not started', () => {
-    expect(sagaExe).not.toHaveBeenCalled();
-  });
-
-  test('it can dispatch store actions once running', async () => {
-    sagaExeReduxMiddleware.start();
-    expect(store.getState()).toEqual({ count: 0 });
-    expect(sagaExe).toHaveBeenCalled();
-
-    store.dispatch({ type: DELAYED_INCREMENT_COUNTER });
-    expect(store.getState()).toEqual({ count: 0 });
-
-    await sleep();
-
-    expect(sideAffect).toHaveBeenCalled();
-    expect(store.getState()).toEqual({ count: 1 });
-  });
-
-  test('it stops processing if break out of loop', async () => {
-    sagaExeReduxMiddleware.start();
-    store.dispatch({ type: DELAYED_INCREMENT_COUNTER });
-    await sleep();
-
-    expect(store.getState()).toEqual({ count: 1 });
-    expect(sideAffect).toHaveBeenCalledTimes(2);
-
-    store.dispatch({ type: STOP_SAGA_PROCESSING });
-    await sleep();
-
-    store.dispatch({ type: DELAYED_INCREMENT_COUNTER });
-    await sleep();
-
-    expect(store.getState()).toEqual({ count: 1 });
-    expect(sideAffect).toHaveBeenCalledTimes(2);
-  });
-
-  test('it stops saga middleware when stop() is called', async () => {
-    sagaExeReduxMiddleware.start();
-    store.dispatch({ type: DELAYED_INCREMENT_COUNTER });
-    await sleep();
-
-    expect(store.getState()).toEqual({ count: 1 });
-    expect(sideAffect).toHaveBeenCalledTimes(2);
-
-    sagaExeReduxMiddleware.stop();
-
-    store.dispatch({ type: DELAYED_INCREMENT_COUNTER });
-    await sleep();
-
-    expect(store.getState()).toEqual({ count: 1 });
-    expect(sideAffect).toHaveBeenCalledTimes(2);
-  });
-});
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.ts b/x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.ts
deleted file mode 100644
index 2a79827847f2e..0000000000000
--- a/x-pack/plugins/endpoint/public/applications/endpoint/lib/saga.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { AnyAction, Dispatch, Middleware, MiddlewareAPI } from 'redux';
-import { GlobalState } from '../types';
-
-interface QueuedAction<TAction = AnyAction> {
-  /**
-   * The Redux action that was dispatched
-   */
-  action: TAction;
-  /**
-   * The Global state at the time the action was dispatched
-   */
-  state: GlobalState;
-}
-
-interface IteratorInstance {
-  queue: QueuedAction[];
-  nextResolve: null | ((inst: QueuedAction) => void);
-}
-
-type Saga = (storeContext: SagaContext) => Promise<void>;
-
-type StoreActionsAndState<TAction = AnyAction> = AsyncIterableIterator<QueuedAction<TAction>>;
-
-export interface SagaContext<TAction extends AnyAction = AnyAction> {
-  /**
-   * A generator function that will `yield` `Promise`s that resolve with a `QueuedAction`
-   */
-  actionsAndState: () => StoreActionsAndState<TAction>;
-  dispatch: Dispatch<TAction>;
-}
-
-export interface SagaMiddleware extends Middleware {
-  /**
-   * Start the saga. Should be called after the `store` has been created
-   */
-  start: () => void;
-
-  /**
-   * Stop the saga by exiting the internal generator `for await...of` loop.
-   */
-  stop: () => void;
-}
-
-const noop = () => {};
-const STOP = Symbol('STOP');
-
-/**
- * Creates Saga Middleware for use with Redux.
- *
- * @param {Saga} saga The `saga` should initialize a long-running `for await...of` loop against
- * the return value of the `actionsAndState()` method provided by the `SagaContext`.
- *
- * @return {SagaMiddleware}
- *
- * @example
- *
- * type TPossibleActions = { type: 'add', payload: any[] };
- * //...
- * const endpointsSaga = async ({ actionsAndState, dispatch }: SagaContext<TPossibleActions>) => {
- *   for await (const { action, state } of actionsAndState()) {
- *     if (action.type === "userRequestedResource") {
- *       const resourceData = await doApiFetch('of/some/resource');
- *       dispatch({
- *         type: 'add',
- *         payload: [ resourceData ]
- *       });
- *     }
- *   }
- * }
- * const endpointsSagaMiddleware = createSagaMiddleware(endpointsSaga);
- * //....
- * const store = createStore(reducers, [ endpointsSagaMiddleware ]);
- */
-export function createSagaMiddleware(saga: Saga): SagaMiddleware {
-  const iteratorInstances = new Set<IteratorInstance>();
-  let runSaga: () => void = noop;
-  let stopSaga: () => void = noop;
-  let runningPromise: Promise<symbol>;
-
-  async function* getActionsAndStateIterator(): StoreActionsAndState {
-    const instance: IteratorInstance = { queue: [], nextResolve: null };
-    iteratorInstances.add(instance);
-
-    try {
-      while (true) {
-        const actionAndState = await Promise.race([nextActionAndState(), runningPromise]);
-
-        if (actionAndState === STOP) {
-          break;
-        }
-
-        yield actionAndState as QueuedAction;
-      }
-    } finally {
-      // If the consumer stops consuming this (e.g. `break` or `return` is called in the `for await`
-      // then this `finally` block will run and unregister this instance and reset `runSaga`
-      iteratorInstances.delete(instance);
-      runSaga = stopSaga = noop;
-    }
-
-    function nextActionAndState() {
-      if (instance.queue.length) {
-        return Promise.resolve(instance.queue.shift() as QueuedAction);
-      } else {
-        return new Promise<QueuedAction>(function(resolve) {
-          instance.nextResolve = resolve;
-        });
-      }
-    }
-  }
-
-  function enqueue(value: QueuedAction) {
-    for (const iteratorInstance of iteratorInstances) {
-      iteratorInstance.queue.push(value);
-      if (iteratorInstance.nextResolve !== null) {
-        iteratorInstance.nextResolve(iteratorInstance.queue.shift() as QueuedAction);
-        iteratorInstance.nextResolve = null;
-      }
-    }
-  }
-
-  function middleware({ getState, dispatch }: MiddlewareAPI) {
-    if (runSaga === noop) {
-      runSaga = saga.bind<null, SagaContext, any[], Promise<void>>(null, {
-        actionsAndState: getActionsAndStateIterator,
-        dispatch,
-      });
-    }
-    return (next: Dispatch<AnyAction>) => (action: AnyAction) => {
-      // Call the next dispatch method in the middleware chain.
-      const returnValue = next(action);
-
-      enqueue({
-        action,
-        state: getState(),
-      });
-
-      // This will likely be the action itself, unless a middleware further in chain changed it.
-      return returnValue;
-    };
-  }
-
-  middleware.start = () => {
-    runningPromise = new Promise(resolve => (stopSaga = () => resolve(STOP)));
-    runSaga();
-  };
-
-  middleware.stop = () => {
-    stopSaga();
-  };
-
-  return middleware;
-}

From f96f928e6990d64cd7abdb4bedadc1d84557d39c Mon Sep 17 00:00:00 2001
From: Wylie Conlon <william.conlon@elastic.co>
Date: Fri, 10 Apr 2020 12:29:26 -0400
Subject: [PATCH 55/78] [Lens] Fix error in query from generated suggestion
 (#63018)

* [Lens] Fix error in query from generated suggestion

* Update from review comments

* Fix test

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../indexpattern_suggestions.test.tsx             |  4 ++--
 .../indexpattern_suggestions.ts                   | 15 +++++++--------
 .../operations/definitions/terms.test.tsx         |  2 +-
 .../operations/definitions/terms.tsx              |  2 +-
 4 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx
index e36622f876acd..fe14e5de5c1e3 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx
@@ -824,10 +824,10 @@ describe('IndexPattern Data Source suggestions', () => {
             state: expect.objectContaining({
               layers: expect.objectContaining({
                 currentLayer: expect.objectContaining({
-                  columnOrder: ['cola', 'id1'],
+                  columnOrder: ['cola', 'colb'],
                   columns: {
                     cola: initialState.layers.currentLayer.columns.cola,
-                    id1: expect.objectContaining({
+                    colb: expect.objectContaining({
                       operationType: 'avg',
                       sourceField: 'memory',
                     }),
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts
index 96127caa67bb4..d339171a5ae1f 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts
@@ -15,8 +15,8 @@ import {
   operationDefinitionMap,
   IndexPatternColumn,
 } from './operations';
-import { hasField } from './utils';
 import { operationDefinitions } from './operations/definitions';
+import { hasField } from './utils';
 import {
   IndexPattern,
   IndexPatternPrivateState,
@@ -196,7 +196,7 @@ function addFieldAsMetricOperation(
     suggestedPriority: undefined,
     field,
   });
-  const newColumnId = generateId();
+  const addedColumnId = generateId();
 
   const [, metrics] = separateBucketColumns(layer);
 
@@ -206,20 +206,19 @@ function addFieldAsMetricOperation(
       indexPatternId: indexPattern.id,
       columns: {
         ...layer.columns,
-        [newColumnId]: newColumn,
+        [addedColumnId]: newColumn,
       },
-      columnOrder: [...layer.columnOrder, newColumnId],
+      columnOrder: [...layer.columnOrder, addedColumnId],
     };
   }
 
-  // If only one metric, replace instead of add
-  const newColumns = { ...layer.columns, [newColumnId]: newColumn };
-  delete newColumns[metrics[0]];
+  // Replacing old column with new column, keeping the old ID
+  const newColumns = { ...layer.columns, [metrics[0]]: newColumn };
 
   return {
     indexPatternId: indexPattern.id,
     columns: newColumns,
-    columnOrder: [...layer.columnOrder.filter(c => c !== metrics[0]), newColumnId],
+    columnOrder: layer.columnOrder, // Order is kept by replacing
   };
 }
 
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx
index 226246714f18d..fc0c9746b2f98 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx
@@ -274,7 +274,7 @@ describe('terms', () => {
       expect(updatedColumn).toBe(initialColumn);
     });
 
-    it('should switch to alphabetical ordering if the order column is removed', () => {
+    it('should switch to alphabetical ordering if there are no columns to order by', () => {
       const termsColumn = termsOperation.onOtherColumnChanged!(
         {
           label: 'Top value of category',
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.tsx
index cd0dcc0b7e9ce..387b197c9235c 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.tsx
@@ -135,7 +135,7 @@ export const termsOperation: OperationDefinition<TermsIndexPatternColumn> = {
     }
     return currentColumn;
   },
-  paramEditor: ({ state, setState, currentColumn, columnId: currentColumnId, layerId }) => {
+  paramEditor: ({ state, setState, currentColumn, layerId }) => {
     const SEPARATOR = '$$$';
     function toValue(orderBy: TermsIndexPatternColumn['params']['orderBy']) {
       if (orderBy.type === 'alphabetical') {

From 9d2ecc7c06d16ece27449fe2907801024dd438ec Mon Sep 17 00:00:00 2001
From: Brent Kimmel <bkimmel@users.noreply.github.com>
Date: Fri, 10 Apr 2020 12:38:26 -0400
Subject: [PATCH 56/78] Resolver/node svg 2 html (#62958)

* Remove some SVG in Resolver nodes and replace with HTML
---
 .../public/embeddables/resolver/view/defs.tsx |  44 +---
 .../resolver/view/process_event_dot.tsx       | 199 ++++++++++--------
 2 files changed, 113 insertions(+), 130 deletions(-)

diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx b/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx
index 8ee9bfafc630e..de9c3c7e8f8f3 100644
--- a/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx
+++ b/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx
@@ -5,7 +5,7 @@
  */
 
 import React, { memo } from 'react';
-import { saturate, lighten } from 'polished';
+import { saturate } from 'polished';
 
 import {
   htmlIdGenerator,
@@ -79,8 +79,6 @@ const idGenerator = htmlIdGenerator();
  * Ids of paint servers to be referenced by fill and stroke attributes
  */
 export const PaintServerIds = {
-  runningProcess: idGenerator('psRunningProcess'),
-  runningTrigger: idGenerator('psRunningTrigger'),
   runningProcessCube: idGenerator('psRunningProcessCube'),
   runningTriggerCube: idGenerator('psRunningTriggerCube'),
   terminatedProcessCube: idGenerator('psTerminatedProcessCube'),
@@ -93,46 +91,6 @@ export const PaintServerIds = {
  */
 const PaintServers = memo(() => (
   <>
-    <linearGradient
-      id={PaintServerIds.runningProcess}
-      x1="0"
-      y1="0"
-      x2="1"
-      y2="0"
-      spreadMethod="reflect"
-      gradientUnits="objectBoundingBox"
-    >
-      <stop
-        offset="0%"
-        stopColor={saturate(0.7, lighten(0.05, NamedColors.runningProcessStart))}
-        stopOpacity="1"
-      />
-      <stop
-        offset="100%"
-        stopColor={saturate(0.7, lighten(0.05, NamedColors.runningProcessEnd))}
-        stopOpacity="1"
-      />
-    </linearGradient>
-    <linearGradient
-      id={PaintServerIds.runningTrigger}
-      x1="0"
-      y1="0"
-      x2="1"
-      y2="0"
-      spreadMethod="reflect"
-      gradientUnits="objectBoundingBox"
-    >
-      <stop
-        offset="0%"
-        stopColor={saturate(0.7, lighten(0.05, NamedColors.runningTriggerStart))}
-        stopOpacity="1"
-      />
-      <stop
-        offset="100%"
-        stopColor={saturate(0.7, lighten(0.05, NamedColors.runningTriggerEnd))}
-        stopOpacity="1"
-      />
-    </linearGradient>
     <linearGradient
       id={PaintServerIds.terminatedProcessCube}
       x1="-381.23752"
diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx b/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx
index 2e3981de74d34..10e331ffff02d 100644
--- a/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx
+++ b/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx
@@ -11,7 +11,7 @@ import { htmlIdGenerator, EuiKeyboardAccessible } from '@elastic/eui';
 import { useSelector } from 'react-redux';
 import { applyMatrix3 } from '../lib/vector2';
 import { Vector2, Matrix3, AdjacentProcessMap, ResolverProcessType } from '../types';
-import { SymbolIds, NamedColors, PaintServerIds } from './defs';
+import { SymbolIds, NamedColors } from './defs';
 import { ResolverEvent } from '../../../../common/types';
 import { useResolverDispatch } from './use_resolver_dispatch';
 import * as eventModel from '../../../../common/models/event';
@@ -21,7 +21,7 @@ import * as selectors from '../store/selectors';
 const nodeAssets = {
   runningProcessCube: {
     cubeSymbol: `#${SymbolIds.runningProcessCube}`,
-    labelFill: `url(#${PaintServerIds.runningProcess})`,
+    labelBackground: NamedColors.fullLabelBackground,
     descriptionFill: NamedColors.empty,
     descriptionText: i18n.translate('xpack.endpoint.resolver.runningProcess', {
       defaultMessage: 'Running Process',
@@ -29,7 +29,7 @@ const nodeAssets = {
   },
   runningTriggerCube: {
     cubeSymbol: `#${SymbolIds.runningTriggerCube}`,
-    labelFill: `url(#${PaintServerIds.runningTrigger})`,
+    labelBackground: NamedColors.fullLabelBackground,
     descriptionFill: NamedColors.empty,
     descriptionText: i18n.translate('xpack.endpoint.resolver.runningTrigger', {
       defaultMessage: 'Running Trigger',
@@ -37,7 +37,7 @@ const nodeAssets = {
   },
   terminatedProcessCube: {
     cubeSymbol: `#${SymbolIds.terminatedProcessCube}`,
-    labelFill: NamedColors.fullLabelBackground,
+    labelBackground: NamedColors.fullLabelBackground,
     descriptionFill: NamedColors.empty,
     descriptionText: i18n.translate('xpack.endpoint.resolver.terminatedProcess', {
       defaultMessage: 'Terminated Process',
@@ -45,7 +45,7 @@ const nodeAssets = {
   },
   terminatedTriggerCube: {
     cubeSymbol: `#${SymbolIds.terminatedTriggerCube}`,
-    labelFill: NamedColors.fullLabelBackground,
+    labelBackground: NamedColors.fullLabelBackground,
     descriptionFill: NamedColors.empty,
     descriptionText: i18n.translate('xpack.endpoint.resolver.terminatedTrigger', {
       defaultMessage: 'Terminated Trigger',
@@ -114,14 +114,21 @@ export const ProcessEventDot = styled(
         [left, magFactorX, top]
       );
 
+      /**
+       * Type in non-SVG components scales as follows:
+       *  (These values were adjusted to match the proportions in the comps provided by UX/Design)
+       *  18.75 : The smallest readable font size at which labels/descriptions can be read. Font size will not scale below this.
+       *  12.5 : A 'slope' at which the font size will scale w.r.t. to zoom level otherwise
+       */
+      const minimumFontSize = 18.75;
+      const slopeOfFontScale = 12.5;
+      const fontSizeAdjustmentForScale = magFactorX > 1 ? slopeOfFontScale * (magFactorX - 1) : 0;
+      const scaledTypeSize = minimumFontSize + fontSizeAdjustmentForScale;
+
       const markerBaseSize = 15;
       const markerSize = markerBaseSize;
       const markerPositionOffset = -markerBaseSize / 2;
 
-      const labelYOffset = markerPositionOffset + 0.25 * markerSize - 0.5;
-
-      const labelYHeight = markerSize / 1.7647;
-
       /**
        * An element that should be animated when the node is clicked.
        */
@@ -136,9 +143,7 @@ export const ProcessEventDot = styled(
             })
           | null;
       } = React.createRef();
-      const { cubeSymbol, labelFill, descriptionFill, descriptionText } = nodeAssets[
-        nodeType(event)
-      ];
+      const { cubeSymbol, labelBackground, descriptionText } = nodeAssets[nodeType(event)];
       const resolverNodeIdGenerator = useMemo(() => htmlIdGenerator('resolverNode'), []);
 
       const nodeId = useMemo(() => resolverNodeIdGenerator(selfId), [
@@ -154,7 +159,7 @@ export const ProcessEventDot = styled(
       const dispatch = useResolverDispatch();
 
       const handleFocus = useCallback(
-        (focusEvent: React.FocusEvent<SVGSVGElement>) => {
+        (focusEvent: React.FocusEvent<HTMLDivElement>) => {
           dispatch({
             type: 'userFocusedOnResolverNode',
             payload: {
@@ -166,7 +171,7 @@ export const ProcessEventDot = styled(
       );
 
       const handleClick = useCallback(
-        (clickEvent: React.MouseEvent<SVGSVGElement, MouseEvent>) => {
+        (clickEvent: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
           if (animationTarget.current !== null) {
             (animationTarget.current as any).beginElement();
           }
@@ -179,14 +184,15 @@ export const ProcessEventDot = styled(
         },
         [animationTarget, dispatch, nodeId]
       );
-
+      /* eslint-disable jsx-a11y/click-events-have-key-events */
+      /**
+       * Key event handling (e.g. 'Enter'/'Space') is provisioned by the `EuiKeyboardAccessible` component
+       */
       return (
         <EuiKeyboardAccessible>
-          <svg
+          <div
             data-test-subj={'resolverNode'}
             className={className + ' kbn-resetFocusState'}
-            viewBox="-15 -15 90 30"
-            preserveAspectRatio="xMidYMid meet"
             role="treeitem"
             aria-level={adjacentNodeMap.level}
             aria-flowto={
@@ -203,81 +209,100 @@ export const ProcessEventDot = styled(
             onFocus={handleFocus}
             tabIndex={-1}
           >
-            <g>
-              <use
-                xlinkHref={`#${SymbolIds.processCubeActiveBacking}`}
-                x={-11.35}
-                y={-11.35}
-                width={markerSize * 1.5}
-                height={markerSize * 1.5}
-                className="backing"
-              />
-              <rect x="7" y="-12.75" width="15" height="10" fill={NamedColors.resolverBackground} />
-              <use
-                role="presentation"
-                xlinkHref={cubeSymbol}
-                x={markerPositionOffset}
-                y={markerPositionOffset}
-                width={markerSize}
-                height={markerSize}
-                opacity="1"
-                className="cube"
-              >
-                <animateTransform
-                  attributeType="XML"
-                  attributeName="transform"
-                  type="scale"
-                  values="1 1; 1 .83; 1 .8; 1 .83; 1 1"
-                  dur="0.2s"
-                  begin="click"
-                  repeatCount="1"
-                  className="squish"
-                  ref={animationTarget}
+            <svg
+              viewBox="-15 -15 90 30"
+              preserveAspectRatio="xMidYMid meet"
+              style={{
+                display: 'block',
+                width: '100%',
+                height: '100%',
+                position: 'absolute',
+                top: '0',
+                left: '0',
+              }}
+            >
+              <g>
+                <use
+                  xlinkHref={`#${SymbolIds.processCubeActiveBacking}`}
+                  x={-11.35}
+                  y={-11.35}
+                  width={markerSize * 1.5}
+                  height={markerSize * 1.5}
+                  className="backing"
                 />
-              </use>
-              <use
-                role="presentation"
-                xlinkHref={`#${SymbolIds.processNodeLabel}`}
-                x={markerPositionOffset + markerSize - 0.5}
-                y={labelYOffset}
-                width={(markerSize / 1.7647) * 5}
-                height={markerSize / 1.7647}
-                opacity="1"
-                fill={labelFill}
-              />
-              <text
-                x={markerPositionOffset + 0.7 * markerSize + 50 / 2}
-                y={labelYOffset + labelYHeight / 2}
-                textAnchor="middle"
-                dominantBaseline="middle"
-                fontSize="3.75"
-                fontWeight="bold"
-                fill={NamedColors.empty}
-                paintOrder="stroke"
-                tabIndex={-1}
-                style={{ letterSpacing: '-0.02px' }}
-                id={labelId}
-              >
-                {eventModel.eventName(event)}
-              </text>
-              <text
-                x={markerPositionOffset + markerSize}
-                y={labelYOffset - 1}
-                textAnchor="start"
-                dominantBaseline="middle"
-                fontSize="2.67"
-                fill={descriptionFill}
+                <use
+                  role="presentation"
+                  xlinkHref={cubeSymbol}
+                  x={markerPositionOffset}
+                  y={markerPositionOffset}
+                  width={markerSize}
+                  height={markerSize}
+                  opacity="1"
+                  className="cube"
+                >
+                  <animateTransform
+                    attributeType="XML"
+                    attributeName="transform"
+                    type="scale"
+                    values="1 1; 1 .83; 1 .8; 1 .83; 1 1"
+                    dur="0.2s"
+                    begin="click"
+                    repeatCount="1"
+                    className="squish"
+                    ref={animationTarget}
+                  />
+                </use>
+              </g>
+            </svg>
+            <div
+              style={{
+                left: '25%',
+                top: '30%',
+                position: 'absolute',
+                width: '50%',
+                color: 'white',
+                fontSize: `${scaledTypeSize}px`,
+                lineHeight: '140%',
+              }}
+            >
+              <div
                 id={descriptionId}
-                paintOrder="stroke"
-                fontWeight="bold"
-                style={{ textTransform: 'uppercase', letterSpacing: '-0.01px' }}
+                style={{
+                  textTransform: 'uppercase',
+                  letterSpacing: '-0.01px',
+                  backgroundColor: NamedColors.resolverBackground,
+                  lineHeight: '1.2',
+                  fontWeight: 'bold',
+                  fontSize: '.5em',
+                  width: '100%',
+                  margin: '0 0 .05em 0',
+                  textAlign: 'left',
+                  padding: '0',
+                }}
               >
                 {descriptionText}
-              </text>
-            </g>
-          </svg>
+              </div>
+              <div
+                data-test-subject="nodeLabel"
+                id={labelId}
+                style={{
+                  backgroundColor: labelBackground,
+                  padding: '.15em 0',
+                  textAlign: 'center',
+                  maxWidth: '100%',
+                  overflow: 'hidden',
+                  whiteSpace: 'nowrap',
+                  textOverflow: 'ellipsis',
+                  contain: 'content',
+                }}
+              >
+                {eventModel.eventName(event)}
+              </div>
+            </div>
+          </div>
         </EuiKeyboardAccessible>
       );
+      /* eslint-enable jsx-a11y/click-events-have-key-events */
     }
   )
 )`

From aed5253b53fdf53781b6220dbe937510cb7ed378 Mon Sep 17 00:00:00 2001
From: Tim Sullivan <tsullivan@users.noreply.github.com>
Date: Fri, 10 Apr 2020 09:57:59 -0700
Subject: [PATCH 57/78] [Reporting] convert all server unit tests to TypeScript
 (#62873)

* [Reporting] convert all server unit tests to TypeScript

* fix ts

* revert unrelated change
---
 ...{index.test.js.snap => index.test.ts.snap} |   0
 ...xecute_job.test.js => execute_job.test.ts} | 227 ++++++++++--------
 .../{index.test.js => index.test.ts}          |  61 +++--
 .../{index.test.js => index.test.ts}          |  52 ++--
 .../{index.test.js => index.test.ts}          |   2 +-
 .../routes/{jobs.test.js => jobs.test.ts}     |  36 +--
 ...t.js => reporting_usage_collector.test.ts} |  58 +++--
 .../create_mock_browserdriverfactory.ts       |   2 +-
 x-pack/legacy/plugins/reporting/types.d.ts    |   2 +-
 9 files changed, 273 insertions(+), 167 deletions(-)
 rename x-pack/legacy/plugins/reporting/__snapshots__/{index.test.js.snap => index.test.ts.snap} (100%)
 rename x-pack/legacy/plugins/reporting/export_types/csv/server/{execute_job.test.js => execute_job.test.ts} (88%)
 rename x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/{index.test.js => index.test.ts} (58%)
 rename x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/{index.test.js => index.test.ts} (57%)
 rename x-pack/legacy/plugins/reporting/{index.test.js => index.test.ts} (94%)
 rename x-pack/legacy/plugins/reporting/server/routes/{jobs.test.js => jobs.test.ts} (91%)
 rename x-pack/legacy/plugins/reporting/server/usage/{reporting_usage_collector.test.js => reporting_usage_collector.test.ts} (90%)

diff --git a/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap b/x-pack/legacy/plugins/reporting/__snapshots__/index.test.ts.snap
similarity index 100%
rename from x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap
rename to x-pack/legacy/plugins/reporting/__snapshots__/index.test.ts.snap
diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts
similarity index 88%
rename from x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js
rename to x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts
index 4870e1e35cdaf..f0afade8629ab 100644
--- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js
+++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts
@@ -4,6 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
+// @ts-ignore
 import Puid from 'puid';
 import sinon from 'sinon';
 import nodeCrypto from '@elastic/node-crypto';
@@ -13,36 +14,40 @@ import { createMockReportingCore } from '../../../test_helpers';
 import { LevelLogger } from '../../../server/lib/level_logger';
 import { setFieldFormats } from '../../../server/services';
 import { executeJobFactory } from './execute_job';
+import { JobDocPayloadDiscoverCsv } from '../types';
 import { CSV_BOM_CHARS } from '../../../common/constants';
 
-const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
+const delay = (ms: number) => new Promise(resolve => setTimeout(() => resolve(), ms));
 
 const puid = new Puid();
 const getRandomScrollId = () => {
   return puid.generate();
 };
 
+const getJobDocPayload = (baseObj: any) => baseObj as JobDocPayloadDiscoverCsv;
+
 describe('CSV Execute Job', function() {
   const encryptionKey = 'testEncryptionKey';
   const headers = {
     sid: 'test',
   };
   const mockLogger = new LevelLogger({
-    get: () => ({
-      debug: jest.fn(),
-      warn: jest.fn(),
-      error: jest.fn(),
-    }),
+    get: () =>
+      ({
+        debug: jest.fn(),
+        warn: jest.fn(),
+        error: jest.fn(),
+      } as any),
   });
-  let defaultElasticsearchResponse;
-  let encryptedHeaders;
+  let defaultElasticsearchResponse: any;
+  let encryptedHeaders: any;
 
-  let clusterStub;
-  let configGetStub;
-  let mockReportingConfig;
-  let mockReportingPlugin;
-  let callAsCurrentUserStub;
-  let cancellationToken;
+  let clusterStub: any;
+  let configGetStub: any;
+  let mockReportingConfig: any;
+  let mockReportingPlugin: any;
+  let callAsCurrentUserStub: any;
+  let cancellationToken: any;
 
   const mockElasticsearch = {
     dataClient: {
@@ -78,7 +83,7 @@ describe('CSV Execute Job', function() {
       _scroll_id: 'defaultScrollId',
     };
     clusterStub = {
-      callAsCurrentUser: function() {},
+      callAsCurrentUser() {},
     };
 
     callAsCurrentUserStub = sinon
@@ -89,17 +94,19 @@ describe('CSV Execute Job', function() {
     mockUiSettingsClient.get.withArgs('csv:quoteValues').returns(true);
 
     setFieldFormats({
-      fieldFormatServiceFactory: function() {
+      fieldFormatServiceFactory() {
         const uiConfigMock = {};
-        uiConfigMock['format:defaultTypeMap'] = {
+        (uiConfigMock as any)['format:defaultTypeMap'] = {
           _default_: { id: 'string', params: {} },
         };
 
         const fieldFormatsRegistry = new fieldFormats.FieldFormatsRegistry();
 
-        fieldFormatsRegistry.init(key => uiConfigMock[key], {}, [fieldFormats.StringFormat]);
+        fieldFormatsRegistry.init(key => (uiConfigMock as any)[key], {}, [
+          fieldFormats.StringFormat,
+        ]);
 
-        return fieldFormatsRegistry;
+        return Promise.resolve(fieldFormatsRegistry);
       },
     });
   });
@@ -109,7 +116,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       await executeJob(
         'job456',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
       expect(callAsCurrentUserStub.called).toBe(true);
@@ -123,14 +134,14 @@ describe('CSV Execute Job', function() {
       };
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const job = {
+      const job = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: {
           index,
           body,
         },
-      };
+      });
 
       await executeJob('job777', job, cancellationToken);
 
@@ -152,7 +163,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       await executeJob(
         'job456',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
 
@@ -166,7 +181,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       await executeJob(
         'job456',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
 
@@ -196,7 +215,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       await executeJob(
         'job456',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
 
@@ -231,7 +254,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       await executeJob(
         'job456',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
 
@@ -257,12 +284,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: undefined,
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(`[TypeError: Cannot read property 'indexOf' of undefined]`);
@@ -284,12 +311,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { csv_contains_formulas: csvContainsFormulas } = await executeJob(
         'job123',
         jobParams,
@@ -309,12 +336,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['=SUM(A1:A2)', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { csv_contains_formulas: csvContainsFormulas } = await executeJob(
         'job123',
         jobParams,
@@ -334,12 +361,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { csv_contains_formulas: csvContainsFormulas } = await executeJob(
         'job123',
         jobParams,
@@ -359,12 +386,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { csv_contains_formulas: csvContainsFormulas } = await executeJob(
         'job123',
         jobParams,
@@ -386,12 +413,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
 
       expect(content).toEqual(`${CSV_BOM_CHARS}one,two\none,bar\n`);
@@ -407,12 +434,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
 
       expect(content).toEqual('one,two\none,bar\n');
@@ -423,11 +450,11 @@ describe('CSV Execute Job', function() {
     it('should reject Promise if search call errors out', async function() {
       callAsCurrentUserStub.rejects(new Error());
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(`[Error]`);
@@ -442,11 +469,11 @@ describe('CSV Execute Job', function() {
       });
       callAsCurrentUserStub.onSecondCall().rejects(new Error());
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(`[Error]`);
@@ -463,11 +490,11 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(
@@ -484,11 +511,11 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(
@@ -512,11 +539,11 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(
@@ -540,11 +567,11 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       await expect(
         executeJob('job123', jobParams, cancellationToken)
       ).rejects.toMatchInlineSnapshot(
@@ -578,7 +605,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       executeJob(
         'job345',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
 
@@ -593,13 +624,17 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       executeJob(
         'job345',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
       cancellationToken.cancel();
 
       for (let i = 0; i < callAsCurrentUserStub.callCount; ++i) {
-        expect(callAsCurrentUserStub.getCall(i).args[1]).to.not.be('clearScroll');
+        expect(callAsCurrentUserStub.getCall(i).args[1]).not.toBe('clearScroll'); // dead code?
       }
     });
 
@@ -607,7 +642,11 @@ describe('CSV Execute Job', function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
       executeJob(
         'job345',
-        { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } },
+        getJobDocPayload({
+          headers: encryptedHeaders,
+          fields: [],
+          searchRequest: { index: null, body: null },
+        }),
         cancellationToken
       );
       await delay(100);
@@ -623,11 +662,11 @@ describe('CSV Execute Job', function() {
   describe('csv content', function() {
     it('should write column headers to output, even if there are no results', async function() {
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       expect(content).toBe(`one,two\n`);
     });
@@ -635,11 +674,11 @@ describe('CSV Execute Job', function() {
     it('should use custom uiSettings csv:separator for header', async function() {
       mockUiSettingsClient.get.withArgs('csv:separator').returns(';');
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       expect(content).toBe(`one;two\n`);
     });
@@ -647,11 +686,11 @@ describe('CSV Execute Job', function() {
     it('should escape column headers if uiSettings csv:quoteValues is true', async function() {
       mockUiSettingsClient.get.withArgs('csv:quoteValues').returns(true);
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one and a half', 'two', 'three-and-four', 'five & six'],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       expect(content).toBe(`"one and a half",two,"three-and-four","five & six"\n`);
     });
@@ -659,11 +698,11 @@ describe('CSV Execute Job', function() {
     it(`shouldn't escape column headers if uiSettings csv:quoteValues is false`, async function() {
       mockUiSettingsClient.get.withArgs('csv:quoteValues').returns(false);
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one and a half', 'two', 'three-and-four', 'five & six'],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       expect(content).toBe(`one and a half,two,three-and-four,five & six\n`);
     });
@@ -677,11 +716,11 @@ describe('CSV Execute Job', function() {
         _scroll_id: 'scrollId',
       });
 
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       const lines = content.split('\n');
       const headerLine = lines[0];
@@ -697,12 +736,12 @@ describe('CSV Execute Job', function() {
         _scroll_id: 'scrollId',
       });
 
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       const lines = content.split('\n');
       const valuesLine = lines[1];
@@ -724,12 +763,12 @@ describe('CSV Execute Job', function() {
         _scroll_id: 'scrollId',
       });
 
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       const lines = content.split('\n');
 
@@ -746,7 +785,7 @@ describe('CSV Execute Job', function() {
         _scroll_id: 'scrollId',
       });
 
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
@@ -760,7 +799,7 @@ describe('CSV Execute Job', function() {
             fieldFormatMap: '{"one":{"id":"string","params":{"transform": "upper"}}}',
           },
         },
-      };
+      });
       const { content } = await executeJob('job123', jobParams, cancellationToken);
       const lines = content.split('\n');
 
@@ -774,18 +813,18 @@ describe('CSV Execute Job', function() {
     // tests use these 'simple' characters to make the math easier
 
     describe('when only the headers exceed the maxSizeBytes', function() {
-      let content;
-      let maxSizeReached;
+      let content: string;
+      let maxSizeReached: boolean;
 
       beforeEach(async function() {
         configGetStub.withArgs('csv', 'maxSizeBytes').returns(1);
 
         const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-        const jobParams = {
+        const jobParams = getJobDocPayload({
           headers: encryptedHeaders,
           fields: ['one', 'two'],
           searchRequest: { index: null, body: null },
-        };
+        });
 
         ({ content, max_size_reached: maxSizeReached } = await executeJob(
           'job123',
@@ -804,18 +843,18 @@ describe('CSV Execute Job', function() {
     });
 
     describe('when headers are equal to maxSizeBytes', function() {
-      let content;
-      let maxSizeReached;
+      let content: string;
+      let maxSizeReached: boolean;
 
       beforeEach(async function() {
         configGetStub.withArgs('csv', 'maxSizeBytes').returns(9);
 
         const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-        const jobParams = {
+        const jobParams = getJobDocPayload({
           headers: encryptedHeaders,
           fields: ['one', 'two'],
           searchRequest: { index: null, body: null },
-        };
+        });
 
         ({ content, max_size_reached: maxSizeReached } = await executeJob(
           'job123',
@@ -834,8 +873,8 @@ describe('CSV Execute Job', function() {
     });
 
     describe('when the data exceeds the maxSizeBytes', function() {
-      let content;
-      let maxSizeReached;
+      let content: string;
+      let maxSizeReached: boolean;
 
       beforeEach(async function() {
         configGetStub.withArgs('csv', 'maxSizeBytes').returns(9);
@@ -848,12 +887,12 @@ describe('CSV Execute Job', function() {
         });
 
         const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-        const jobParams = {
+        const jobParams = getJobDocPayload({
           headers: encryptedHeaders,
           fields: ['one', 'two'],
           conflictedTypesFields: [],
           searchRequest: { index: null, body: null },
-        };
+        });
 
         ({ content, max_size_reached: maxSizeReached } = await executeJob(
           'job123',
@@ -872,8 +911,8 @@ describe('CSV Execute Job', function() {
     });
 
     describe('when headers and data equal the maxSizeBytes', function() {
-      let content;
-      let maxSizeReached;
+      let content: string;
+      let maxSizeReached: boolean;
 
       beforeEach(async function() {
         mockReportingPlugin.getUiSettingsServiceFactory = () => mockUiSettingsClient;
@@ -887,12 +926,12 @@ describe('CSV Execute Job', function() {
         });
 
         const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-        const jobParams = {
+        const jobParams = getJobDocPayload({
           headers: encryptedHeaders,
           fields: ['one', 'two'],
           conflictedTypesFields: [],
           searchRequest: { index: null, body: null },
-        };
+        });
 
         ({ content, max_size_reached: maxSizeReached } = await executeJob(
           'job123',
@@ -924,12 +963,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
 
       await executeJob('job123', jobParams, cancellationToken);
 
@@ -950,12 +989,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
 
       await executeJob('job123', jobParams, cancellationToken);
 
@@ -976,12 +1015,12 @@ describe('CSV Execute Job', function() {
       });
 
       const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger);
-      const jobParams = {
+      const jobParams = getJobDocPayload({
         headers: encryptedHeaders,
         fields: ['one', 'two'],
         conflictedTypesFields: [],
         searchRequest: { index: null, body: null },
-      };
+      });
 
       await executeJob('job123', jobParams, cancellationToken);
 
diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.ts
similarity index 58%
rename from x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js
rename to x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.ts
index cb63e7dad2fdf..c9cba64a732b6 100644
--- a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js
+++ b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.ts
@@ -5,19 +5,22 @@
  */
 
 import * as Rx from 'rxjs';
-import { createMockReportingCore } from '../../../../test_helpers';
+import { createMockReportingCore, createMockBrowserDriverFactory } from '../../../../test_helpers';
 import { cryptoFactory } from '../../../../server/lib/crypto';
 import { executeJobFactory } from './index';
 import { generatePngObservableFactory } from '../lib/generate_png';
+import { CancellationToken } from '../../../../common/cancellation_token';
 import { LevelLogger } from '../../../../server/lib';
+import { ReportingCore, CaptureConfig } from '../../../../server/types';
+import { JobDocPayloadPNG } from '../../types';
 
 jest.mock('../lib/generate_png', () => ({ generatePngObservableFactory: jest.fn() }));
 
-let mockReporting;
+let mockReporting: ReportingCore;
 
-const cancellationToken = {
+const cancellationToken = ({
   on: jest.fn(),
-};
+} as unknown) as CancellationToken;
 
 const mockLoggerFactory = {
   get: jest.fn().mockImplementation(() => ({
@@ -28,12 +31,16 @@ const mockLoggerFactory = {
 };
 const getMockLogger = () => new LevelLogger(mockLoggerFactory);
 
+const captureConfig = {} as CaptureConfig;
+
 const mockEncryptionKey = 'abcabcsecuresecret';
-const encryptHeaders = async headers => {
+const encryptHeaders = async (headers: Record<string, string>) => {
   const crypto = cryptoFactory(mockEncryptionKey);
   return await crypto.encrypt(headers);
 };
 
+const getJobDocPayload = (baseObj: any) => baseObj as JobDocPayloadPNG;
+
 beforeEach(async () => {
   const kbnConfig = {
     'server.basePath': '/sbp',
@@ -45,8 +52,8 @@ beforeEach(async () => {
     'kibanaServer.protocol': 'http',
   };
   const mockReportingConfig = {
-    get: (...keys) => reportingConfig[keys.join('.')],
-    kbnConfig: { get: (...keys) => kbnConfig[keys.join('.')] },
+    get: (...keys: string[]) => (reportingConfig as any)[keys.join('.')],
+    kbnConfig: { get: (...keys: string[]) => (kbnConfig as any)[keys.join('.')] },
   };
 
   mockReporting = await createMockReportingCore(mockReportingConfig);
@@ -60,22 +67,30 @@ beforeEach(async () => {
   mockGetElasticsearch.mockImplementation(() => Promise.resolve(mockElasticsearch));
   mockReporting.getElasticsearchService = mockGetElasticsearch;
 
-  generatePngObservableFactory.mockReturnValue(jest.fn());
+  (generatePngObservableFactory as jest.Mock).mockReturnValue(jest.fn());
 });
 
-afterEach(() => generatePngObservableFactory.mockReset());
+afterEach(() => (generatePngObservableFactory as jest.Mock).mockReset());
 
 test(`passes browserTimezone to generatePng`, async () => {
   const encryptedHeaders = await encryptHeaders({});
+  const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
 
-  const generatePngObservable = generatePngObservableFactory();
-  generatePngObservable.mockReturnValue(Rx.of(Buffer.from('')));
+  const generatePngObservable = generatePngObservableFactory(
+    captureConfig,
+    mockBrowserDriverFactory
+  );
+  (generatePngObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from('')));
 
   const executeJob = await executeJobFactory(mockReporting, getMockLogger());
   const browserTimezone = 'UTC';
   await executeJob(
     'pngJobId',
-    { relativeUrl: '/app/kibana#/something', browserTimezone, headers: encryptedHeaders },
+    getJobDocPayload({
+      relativeUrl: '/app/kibana#/something',
+      browserTimezone,
+      headers: encryptedHeaders,
+    }),
     cancellationToken
   );
 
@@ -92,12 +107,17 @@ test(`returns content_type of application/png`, async () => {
   const executeJob = await executeJobFactory(mockReporting, getMockLogger());
   const encryptedHeaders = await encryptHeaders({});
 
-  const generatePngObservable = generatePngObservableFactory();
-  generatePngObservable.mockReturnValue(Rx.of(Buffer.from('')));
+  const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
+
+  const generatePngObservable = generatePngObservableFactory(
+    captureConfig,
+    mockBrowserDriverFactory
+  );
+  (generatePngObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from('')));
 
   const { content_type: contentType } = await executeJob(
     'pngJobId',
-    { relativeUrl: '/app/kibana#/something', timeRange: {}, headers: encryptedHeaders },
+    getJobDocPayload({ relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }),
     cancellationToken
   );
   expect(contentType).toBe('image/png');
@@ -106,14 +126,19 @@ test(`returns content_type of application/png`, async () => {
 test(`returns content of generatePng getBuffer base64 encoded`, async () => {
   const testContent = 'test content';
 
-  const generatePngObservable = generatePngObservableFactory();
-  generatePngObservable.mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
+  const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
+
+  const generatePngObservable = generatePngObservableFactory(
+    captureConfig,
+    mockBrowserDriverFactory
+  );
+  (generatePngObservable as jest.Mock).mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
 
   const executeJob = await executeJobFactory(mockReporting, getMockLogger());
   const encryptedHeaders = await encryptHeaders({});
   const { content } = await executeJob(
     'pngJobId',
-    { relativeUrl: '/app/kibana#/something', timeRange: {}, headers: encryptedHeaders },
+    getJobDocPayload({ relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }),
     cancellationToken
   );
 
diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.ts
similarity index 57%
rename from x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js
rename to x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.ts
index c6f07f8ad2d34..c3c0d38584bc1 100644
--- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js
+++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.ts
@@ -5,19 +5,24 @@
  */
 
 import * as Rx from 'rxjs';
-import { createMockReportingCore } from '../../../../test_helpers';
+import { createMockReportingCore, createMockBrowserDriverFactory } from '../../../../test_helpers';
 import { cryptoFactory } from '../../../../server/lib/crypto';
-import { executeJobFactory } from './index';
-import { generatePdfObservableFactory } from '../lib/generate_pdf';
 import { LevelLogger } from '../../../../server/lib';
+import { CancellationToken } from '../../../../types';
+import { ReportingCore, CaptureConfig } from '../../../../server/types';
+import { generatePdfObservableFactory } from '../lib/generate_pdf';
+import { JobDocPayloadPDF } from '../../types';
+import { executeJobFactory } from './index';
 
 jest.mock('../lib/generate_pdf', () => ({ generatePdfObservableFactory: jest.fn() }));
 
-let mockReporting;
+let mockReporting: ReportingCore;
 
-const cancellationToken = {
+const cancellationToken = ({
   on: jest.fn(),
-};
+} as unknown) as CancellationToken;
+
+const captureConfig = {} as CaptureConfig;
 
 const mockLoggerFactory = {
   get: jest.fn().mockImplementation(() => ({
@@ -29,11 +34,13 @@ const mockLoggerFactory = {
 const getMockLogger = () => new LevelLogger(mockLoggerFactory);
 
 const mockEncryptionKey = 'testencryptionkey';
-const encryptHeaders = async headers => {
+const encryptHeaders = async (headers: Record<string, string>) => {
   const crypto = cryptoFactory(mockEncryptionKey);
   return await crypto.encrypt(headers);
 };
 
+const getJobDocPayload = (baseObj: any) => baseObj as JobDocPayloadPDF;
+
 beforeEach(async () => {
   const kbnConfig = {
     'server.basePath': '/sbp',
@@ -45,8 +52,8 @@ beforeEach(async () => {
     'kibanaServer.protocol': 'http',
   };
   const mockReportingConfig = {
-    get: (...keys) => reportingConfig[keys.join('.')],
-    kbnConfig: { get: (...keys) => kbnConfig[keys.join('.')] },
+    get: (...keys: string[]) => (reportingConfig as any)[keys.join('.')],
+    kbnConfig: { get: (...keys: string[]) => (kbnConfig as any)[keys.join('.')] },
   };
 
   mockReporting = await createMockReportingCore(mockReportingConfig);
@@ -60,21 +67,26 @@ beforeEach(async () => {
   mockGetElasticsearch.mockImplementation(() => Promise.resolve(mockElasticsearch));
   mockReporting.getElasticsearchService = mockGetElasticsearch;
 
-  generatePdfObservableFactory.mockReturnValue(jest.fn());
+  (generatePdfObservableFactory as jest.Mock).mockReturnValue(jest.fn());
 });
 
-afterEach(() => generatePdfObservableFactory.mockReset());
+afterEach(() => (generatePdfObservableFactory as jest.Mock).mockReset());
 
 test(`returns content_type of application/pdf`, async () => {
-  const executeJob = await executeJobFactory(mockReporting, getMockLogger());
+  const logger = getMockLogger();
+  const executeJob = await executeJobFactory(mockReporting, logger);
+  const mockBrowserDriverFactory = await createMockBrowserDriverFactory(logger);
   const encryptedHeaders = await encryptHeaders({});
 
-  const generatePdfObservable = generatePdfObservableFactory();
-  generatePdfObservable.mockReturnValue(Rx.of(Buffer.from('')));
+  const generatePdfObservable = generatePdfObservableFactory(
+    captureConfig,
+    mockBrowserDriverFactory
+  );
+  (generatePdfObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from('')));
 
   const { content_type: contentType } = await executeJob(
     'pdfJobId',
-    { relativeUrls: [], timeRange: {}, headers: encryptedHeaders },
+    getJobDocPayload({ relativeUrls: [], headers: encryptedHeaders }),
     cancellationToken
   );
   expect(contentType).toBe('application/pdf');
@@ -82,15 +94,19 @@ test(`returns content_type of application/pdf`, async () => {
 
 test(`returns content of generatePdf getBuffer base64 encoded`, async () => {
   const testContent = 'test content';
+  const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
 
-  const generatePdfObservable = generatePdfObservableFactory();
-  generatePdfObservable.mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
+  const generatePdfObservable = generatePdfObservableFactory(
+    captureConfig,
+    mockBrowserDriverFactory
+  );
+  (generatePdfObservable as jest.Mock).mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
 
   const executeJob = await executeJobFactory(mockReporting, getMockLogger());
   const encryptedHeaders = await encryptHeaders({});
   const { content } = await executeJob(
     'pdfJobId',
-    { relativeUrls: [], timeRange: {}, headers: encryptedHeaders },
+    getJobDocPayload({ relativeUrls: [], headers: encryptedHeaders }),
     cancellationToken
   );
 
diff --git a/x-pack/legacy/plugins/reporting/index.test.js b/x-pack/legacy/plugins/reporting/index.test.ts
similarity index 94%
rename from x-pack/legacy/plugins/reporting/index.test.js
rename to x-pack/legacy/plugins/reporting/index.test.ts
index 0d9a717bd7d81..8148adab67874 100644
--- a/x-pack/legacy/plugins/reporting/index.test.js
+++ b/x-pack/legacy/plugins/reporting/index.test.ts
@@ -27,7 +27,7 @@ const describeWithContext = describe.each([
 describeWithContext('config schema with context %j', context => {
   it('produces correct config', async () => {
     const schema = await getConfigSchema(reporting);
-    const value = await schema.validate({}, { context });
+    const value: any = await schema.validate({}, { context });
     value.capture.browser.chromium.disableSandbox = '<platform dependent>';
     await expect(value).toMatchSnapshot();
   });
diff --git a/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js b/x-pack/legacy/plugins/reporting/server/routes/jobs.test.ts
similarity index 91%
rename from x-pack/legacy/plugins/reporting/server/routes/jobs.test.js
rename to x-pack/legacy/plugins/reporting/server/routes/jobs.test.ts
index 9f0de844df369..5c58a7dfa0110 100644
--- a/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js
+++ b/x-pack/legacy/plugins/reporting/server/routes/jobs.test.ts
@@ -6,7 +6,10 @@
 
 import Hapi from 'hapi';
 import { createMockReportingCore } from '../../test_helpers';
+import { ExportTypeDefinition } from '../../types';
 import { ExportTypesRegistry } from '../lib/export_types_registry';
+import { LevelLogger } from '../lib/level_logger';
+import { ReportingConfig, ReportingCore, ReportingSetupDeps } from '../types';
 
 jest.mock('./lib/authorized_user_pre_routing', () => ({
   authorizedUserPreRoutingFactory: () => () => ({}),
@@ -19,14 +22,14 @@ jest.mock('./lib/reporting_feature_pre_routing', () => ({
 
 import { registerJobInfoRoutes } from './jobs';
 
-let mockServer;
-let exportTypesRegistry;
-let mockReportingPlugin;
-let mockReportingConfig;
-const mockLogger = {
+let mockServer: any;
+let exportTypesRegistry: ExportTypesRegistry;
+let mockReportingPlugin: ReportingCore;
+let mockReportingConfig: ReportingConfig;
+const mockLogger = ({
   error: jest.fn(),
   debug: jest.fn(),
-};
+} as unknown) as LevelLogger;
 
 beforeEach(async () => {
   mockServer = new Hapi.Server({ debug: false, port: 8080, routes: { log: { collect: true } } });
@@ -35,38 +38,39 @@ beforeEach(async () => {
     id: 'unencoded',
     jobType: 'unencodedJobType',
     jobContentExtension: 'csv',
-  });
+  } as ExportTypeDefinition<unknown, unknown, unknown, unknown>);
   exportTypesRegistry.register({
     id: 'base64Encoded',
     jobType: 'base64EncodedJobType',
     jobContentEncoding: 'base64',
     jobContentExtension: 'pdf',
-  });
+  } as ExportTypeDefinition<unknown, unknown, unknown, unknown>);
 
   mockReportingConfig = { get: jest.fn(), kbnConfig: { get: jest.fn() } };
   mockReportingPlugin = await createMockReportingCore(mockReportingConfig);
   mockReportingPlugin.getExportTypesRegistry = () => exportTypesRegistry;
 });
 
-const mockPlugins = {
+const mockPlugins = ({
   elasticsearch: {
     adminClient: { callAsInternalUser: jest.fn() },
   },
   security: null,
-};
+} as unknown) as ReportingSetupDeps;
 
-const getHits = (...sources) => {
+const getHits = (...sources: any) => {
   return {
     hits: {
-      hits: sources.map(source => ({ _source: source })),
+      hits: sources.map((source: object) => ({ _source: source })),
     },
   };
 };
 
-const getErrorsFromRequest = request =>
-  request.logs.filter(log => log.tags.includes('error')).map(log => log.error);
+const getErrorsFromRequest = (request: any) =>
+  request.logs.filter((log: any) => log.tags.includes('error')).map((log: any) => log.error);
 
 test(`returns 404 if job not found`, async () => {
+  // @ts-ignore
   mockPlugins.elasticsearch.adminClient = {
     callAsInternalUser: jest.fn().mockReturnValue(Promise.resolve(getHits())),
   };
@@ -84,6 +88,7 @@ test(`returns 404 if job not found`, async () => {
 });
 
 test(`returns 401 if not valid job type`, async () => {
+  // @ts-ignore
   mockPlugins.elasticsearch.adminClient = {
     callAsInternalUser: jest
       .fn()
@@ -103,6 +108,7 @@ test(`returns 401 if not valid job type`, async () => {
 
 describe(`when job is incomplete`, () => {
   const getIncompleteResponse = async () => {
+    // @ts-ignore
     mockPlugins.elasticsearch.adminClient = {
       callAsInternalUser: jest
         .fn()
@@ -149,6 +155,7 @@ describe(`when job is failed`, () => {
       status: 'failed',
       output: { content: 'job failure message' },
     });
+    // @ts-ignore
     mockPlugins.elasticsearch.adminClient = {
       callAsInternalUser: jest.fn().mockReturnValue(Promise.resolve(hits)),
     };
@@ -194,6 +201,7 @@ describe(`when job is completed`, () => {
         title,
       },
     });
+    // @ts-ignore
     mockPlugins.elasticsearch.adminClient = {
       callAsInternalUser: jest.fn().mockReturnValue(Promise.resolve(hits)),
     };
diff --git a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts
similarity index 90%
rename from x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js
rename to x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts
index 929109e66914d..dbc674ce36ec8 100644
--- a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js
+++ b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts
@@ -11,18 +11,21 @@ import {
   registerReportingUsageCollector,
   getReportingUsageCollector,
 } from './reporting_usage_collector';
+import { ReportingConfig } from '../types';
 
 const exportTypesRegistry = getExportTypesRegistry();
 
 function getMockUsageCollection() {
   class MockUsageCollector {
-    constructor(_server, { fetch }) {
+    // @ts-ignore fetch is not used
+    private fetch: any;
+    constructor(_server: any, { fetch }: any) {
       this.fetch = fetch;
     }
   }
   return {
-    makeUsageCollector: options => {
-      return new MockUsageCollector(this, options);
+    makeUsageCollector: (options: any) => {
+      return new MockUsageCollector(null, options);
     },
     registerCollector: sinon.stub(),
   };
@@ -51,7 +54,7 @@ function getPluginsMock(
         xpack_main: mockXpackMain,
       },
     },
-  };
+  } as any;
 }
 
 const getMockReportingConfig = () => ({
@@ -61,13 +64,13 @@ const getMockReportingConfig = () => ({
 const getResponseMock = (customization = {}) => customization;
 
 describe('license checks', () => {
-  let mockConfig;
+  let mockConfig: ReportingConfig;
   beforeAll(async () => {
     mockConfig = getMockReportingConfig();
   });
 
   describe('with a basic license', () => {
-    let usageStats;
+    let usageStats: any;
     beforeAll(async () => {
       const plugins = getPluginsMock({ license: 'basic' });
       const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock()));
@@ -75,9 +78,12 @@ describe('license checks', () => {
         mockConfig,
         plugins.usageCollection,
         plugins.__LEGACY.plugins.xpack_main.info,
-        exportTypesRegistry
+        exportTypesRegistry,
+        function isReady() {
+          return Promise.resolve(true);
+        }
       );
-      usageStats = await fetch(callClusterMock, exportTypesRegistry);
+      usageStats = await fetch(callClusterMock as any);
     });
 
     test('sets enables to true', async () => {
@@ -94,7 +100,7 @@ describe('license checks', () => {
   });
 
   describe('with no license', () => {
-    let usageStats;
+    let usageStats: any;
     beforeAll(async () => {
       const plugins = getPluginsMock({ license: 'none' });
       const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock()));
@@ -102,9 +108,12 @@ describe('license checks', () => {
         mockConfig,
         plugins.usageCollection,
         plugins.__LEGACY.plugins.xpack_main.info,
-        exportTypesRegistry
+        exportTypesRegistry,
+        function isReady() {
+          return Promise.resolve(true);
+        }
       );
-      usageStats = await fetch(callClusterMock, exportTypesRegistry);
+      usageStats = await fetch(callClusterMock as any);
     });
 
     test('sets enables to true', async () => {
@@ -121,7 +130,7 @@ describe('license checks', () => {
   });
 
   describe('with platinum license', () => {
-    let usageStats;
+    let usageStats: any;
     beforeAll(async () => {
       const plugins = getPluginsMock({ license: 'platinum' });
       const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock()));
@@ -129,9 +138,12 @@ describe('license checks', () => {
         mockConfig,
         plugins.usageCollection,
         plugins.__LEGACY.plugins.xpack_main.info,
-        exportTypesRegistry
+        exportTypesRegistry,
+        function isReady() {
+          return Promise.resolve(true);
+        }
       );
-      usageStats = await fetch(callClusterMock, exportTypesRegistry);
+      usageStats = await fetch(callClusterMock as any);
     });
 
     test('sets enables to true', async () => {
@@ -148,7 +160,7 @@ describe('license checks', () => {
   });
 
   describe('with no usage data', () => {
-    let usageStats;
+    let usageStats: any;
     beforeAll(async () => {
       const plugins = getPluginsMock({ license: 'basic' });
       const callClusterMock = jest.fn(() => Promise.resolve({}));
@@ -156,9 +168,12 @@ describe('license checks', () => {
         mockConfig,
         plugins.usageCollection,
         plugins.__LEGACY.plugins.xpack_main.info,
-        exportTypesRegistry
+        exportTypesRegistry,
+        function isReady() {
+          return Promise.resolve(true);
+        }
       );
-      usageStats = await fetch(callClusterMock, exportTypesRegistry);
+      usageStats = await fetch(callClusterMock as any);
     });
 
     test('sets enables to true', async () => {
@@ -179,7 +194,10 @@ describe('data modeling', () => {
       mockConfig,
       plugins.usageCollection,
       plugins.__LEGACY.plugins.xpack_main.info,
-      exportTypesRegistry
+      exportTypesRegistry,
+      function isReady() {
+        return Promise.resolve(true);
+      }
     );
     const callClusterMock = jest.fn(() =>
       Promise.resolve(
@@ -303,7 +321,7 @@ describe('data modeling', () => {
       )
     );
 
-    const usageStats = await fetch(callClusterMock);
+    const usageStats = await fetch(callClusterMock as any);
     expect(usageStats).toMatchInlineSnapshot(`
       Object {
         "PNG": Object {
@@ -406,7 +424,7 @@ describe('Ready for collection observable', () => {
     const makeCollectorSpy = sinon.spy();
     usageCollection.makeUsageCollector = makeCollectorSpy;
 
-    const plugins = getPluginsMock({ usageCollection });
+    const plugins = getPluginsMock({ usageCollection } as any);
     registerReportingUsageCollector(mockReporting, plugins);
 
     const [args] = makeCollectorSpy.firstCall.args;
diff --git a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_browserdriverfactory.ts b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_browserdriverfactory.ts
index 930aa7601b8cb..6e95bed2ecf92 100644
--- a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_browserdriverfactory.ts
+++ b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_browserdriverfactory.ts
@@ -92,7 +92,7 @@ const defaultOpts: CreateMockBrowserDriverFactoryOpts = {
 
 export const createMockBrowserDriverFactory = async (
   logger: Logger,
-  opts: Partial<CreateMockBrowserDriverFactoryOpts>
+  opts: Partial<CreateMockBrowserDriverFactoryOpts> = {}
 ): Promise<HeadlessChromiumDriverFactory> => {
   const captureConfig = {
     timeouts: { openUrl: 30000, waitForElements: 30000, renderComplete: 30000 },
diff --git a/x-pack/legacy/plugins/reporting/types.d.ts b/x-pack/legacy/plugins/reporting/types.d.ts
index 7334a859005e0..eec7da7dc6733 100644
--- a/x-pack/legacy/plugins/reporting/types.d.ts
+++ b/x-pack/legacy/plugins/reporting/types.d.ts
@@ -186,7 +186,7 @@ export type ESQueueWorkerExecuteFn<JobDocPayloadType> = (
   jobId: string,
   job: JobDocPayloadType,
   cancellationToken?: CancellationToken
-) => void;
+) => Promise<any>;
 
 /*
  * ImmediateExecuteFn receives the job doc payload because the payload was

From d8a295dcbc272cfb7479169e2f99c4665c811816 Mon Sep 17 00:00:00 2001
From: Ryland Herrick <ryalnd@gmail.com>
Date: Fri, 10 Apr 2020 14:00:11 -0500
Subject: [PATCH 58/78] [SIEM] Link ML Rule card CTA to license_management
 (#63210)

* Link ML Rule card CTA to license_management

Taking the user directly to the license management page within kibana
(where they could immediately start a trial subscription) is much more
actionable than taking them to the subscriptions marketing page.

* Revert translation key change

Neither of these is totally accurate, and there've already been
translations written for the old one.
---
 .../components/select_rule_type/index.tsx      | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx
index 9d3b37f1788fa..6f3d299da8d45 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx
@@ -19,9 +19,16 @@ import {
 import { isMlRule } from '../../../../../../common/detection_engine/ml_helpers';
 import { RuleType } from '../../../../../../common/detection_engine/types';
 import { FieldHook } from '../../../../../shared_imports';
+import { useKibana } from '../../../../../lib/kibana';
 import * as i18n from './translations';
 
-const MlCardDescription = ({ hasValidLicense = false }: { hasValidLicense?: boolean }) => (
+const MlCardDescription = ({
+  subscriptionUrl,
+  hasValidLicense = false,
+}: {
+  subscriptionUrl: string;
+  hasValidLicense?: boolean;
+}) => (
   <EuiText size="s">
     {hasValidLicense ? (
       i18n.ML_TYPE_DESCRIPTION
@@ -31,7 +38,7 @@ const MlCardDescription = ({ hasValidLicense = false }: { hasValidLicense?: bool
         defaultMessage="Access to ML requires a {subscriptionsLink}."
         values={{
           subscriptionsLink: (
-            <EuiLink href="https://www.elastic.co/subscriptions" target="_blank">
+            <EuiLink href={subscriptionUrl} target="_blank">
               <FormattedMessage
                 id="xpack.siem.components.stepDefineRule.ruleTypeField.subscriptionsLink"
                 defaultMessage="Platinum subscription"
@@ -69,6 +76,9 @@ export const SelectRuleType: React.FC<SelectRuleTypeProps> = ({
   const setMl = useCallback(() => setType('machine_learning'), [setType]);
   const setQuery = useCallback(() => setType('query'), [setType]);
   const mlCardDisabled = isReadOnly || !hasValidLicense || !isMlAdmin;
+  const licensingUrl = useKibana().services.application.getUrlForApp('kibana', {
+    path: '#/management/elasticsearch/license_management',
+  });
 
   return (
     <EuiFormRow
@@ -95,7 +105,9 @@ export const SelectRuleType: React.FC<SelectRuleTypeProps> = ({
           <EuiCard
             data-test-subj="machineLearningRuleType"
             title={i18n.ML_TYPE_TITLE}
-            description={<MlCardDescription hasValidLicense={hasValidLicense} />}
+            description={
+              <MlCardDescription subscriptionUrl={licensingUrl} hasValidLicense={hasValidLicense} />
+            }
             icon={<EuiIcon size="l" type="machineLearningApp" />}
             isDisabled={mlCardDisabled}
             selectable={{

From 8a283de3c5884e21c245b1136f39132eeb2d976f Mon Sep 17 00:00:00 2001
From: CJ Cenizal <cj@cenizal.com>
Date: Fri, 10 Apr 2020 12:05:20 -0700
Subject: [PATCH 59/78] Correctly type ILM's optional dependencies as optional
 (#63255)

And guard against their absence.
---
 .../public/application/services/ui_metric.ts              | 8 +++++---
 x-pack/plugins/index_lifecycle_management/public/types.ts | 2 +-
 .../plugins/index_lifecycle_management/server/plugin.ts   | 2 +-
 x-pack/plugins/index_lifecycle_management/server/types.ts | 2 +-
 4 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
index ca6c0b44d5804..ca987441c7ce9 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
@@ -23,10 +23,12 @@ import {
 
 import { defaultColdPhase, defaultWarmPhase, defaultHotPhase } from '../store/defaults';
 
-export let trackUiMetric: (metricType: UiStatsMetricType, eventName: string) => void;
+export let trackUiMetric = (metricType: UiStatsMetricType, eventName: string) => {};
 
-export function init(usageCollection: UsageCollectionSetup): void {
-  trackUiMetric = usageCollection.reportUiStats.bind(usageCollection, UIM_APP_NAME);
+export function init(usageCollection?: UsageCollectionSetup): void {
+  if (usageCollection) {
+    trackUiMetric = usageCollection.reportUiStats.bind(usageCollection, UIM_APP_NAME);
+  }
 }
 
 export function getUiMetricsForPhases(phases: any): any {
diff --git a/x-pack/plugins/index_lifecycle_management/public/types.ts b/x-pack/plugins/index_lifecycle_management/public/types.ts
index f9e0abae56cb4..178884a7ee679 100644
--- a/x-pack/plugins/index_lifecycle_management/public/types.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/types.ts
@@ -9,7 +9,7 @@ import { ManagementSetup } from '../../../../src/plugins/management/public';
 import { IndexManagementPluginSetup } from '../../index_management/public';
 
 export interface PluginsDependencies {
-  usageCollection: UsageCollectionSetup;
+  usageCollection?: UsageCollectionSetup;
   management: ManagementSetup;
   indexManagement?: IndexManagementPluginSetup;
 }
diff --git a/x-pack/plugins/index_lifecycle_management/server/plugin.ts b/x-pack/plugins/index_lifecycle_management/server/plugin.ts
index 48c50f9a48ee5..faeac67f62a21 100644
--- a/x-pack/plugins/index_lifecycle_management/server/plugin.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/plugin.ts
@@ -75,7 +75,7 @@ export class IndexLifecycleManagementServerPlugin implements Plugin<void, void,
     });
 
     if (config.ui.enabled) {
-      if (indexManagement.indexDataEnricher) {
+      if (indexManagement && indexManagement.indexDataEnricher) {
         indexManagement.indexDataEnricher.add(indexLifecycleDataEnricher);
       }
     }
diff --git a/x-pack/plugins/index_lifecycle_management/server/types.ts b/x-pack/plugins/index_lifecycle_management/server/types.ts
index 7f64c1a47197a..734d05a82000e 100644
--- a/x-pack/plugins/index_lifecycle_management/server/types.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/types.ts
@@ -14,7 +14,7 @@ import { isEsError } from './lib/is_es_error';
 
 export interface Dependencies {
   licensing: LicensingPluginSetup;
-  indexManagement: IndexManagementPluginSetup;
+  indexManagement?: IndexManagementPluginSetup;
 }
 
 export interface RouteDependencies {

From ed5dd0a32542f9f24656dd3aa9c642362d40801b Mon Sep 17 00:00:00 2001
From: Ahmad Bamieh <ahmadbamieh@gmail.com>
Date: Fri, 10 Apr 2020 22:18:11 +0300
Subject: [PATCH 60/78] [Telemetry] use prod keys (#63263)

---
 package.json                                  |  2 +-
 .../server/encryption/encrypt.test.mocks.ts   | 27 +++++++++++++++++++
 .../server/encryption/encrypt.test.ts         | 27 ++++++++++++-------
 .../server/encryption/encrypt.ts              |  2 +-
 .../server/plugin.ts                          |  5 ++--
 yarn.lock                                     |  8 +++---
 6 files changed, 54 insertions(+), 17 deletions(-)
 create mode 100644 src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.mocks.ts

diff --git a/package.json b/package.json
index ec72d5b660345..a5d46e7f2bf40 100644
--- a/package.json
+++ b/package.json
@@ -126,7 +126,7 @@
     "@elastic/filesaver": "1.1.2",
     "@elastic/good": "8.1.1-kibana2",
     "@elastic/numeral": "2.4.0",
-    "@elastic/request-crypto": "1.1.2",
+    "@elastic/request-crypto": "1.1.4",
     "@elastic/ui-ace": "0.2.3",
     "@hapi/good-squeeze": "5.2.1",
     "@hapi/wreck": "^15.0.2",
diff --git a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.mocks.ts b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.mocks.ts
new file mode 100644
index 0000000000000..9a7cb8ba28d04
--- /dev/null
+++ b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.mocks.ts
@@ -0,0 +1,27 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const mockEncrypt = jest.fn();
+export const createRequestEncryptor = jest.fn().mockResolvedValue({
+  encrypt: mockEncrypt,
+});
+
+jest.doMock('@elastic/request-crypto', () => ({
+  createRequestEncryptor,
+}));
diff --git a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts
index 4a4ba7aa1f321..c04625eb1dd42 100644
--- a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts
+++ b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts
@@ -16,16 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
+import { createRequestEncryptor, mockEncrypt } from './encrypt.test.mocks';
 import { telemetryJWKS } from './telemetry_jwks';
 import { encryptTelemetry, getKID } from './encrypt';
-import { createRequestEncryptor } from '@elastic/request-crypto';
-
-jest.mock('@elastic/request-crypto', () => ({
-  createRequestEncryptor: jest.fn().mockResolvedValue({
-    encrypt: jest.fn(),
-  }),
-}));
 
 describe('getKID', () => {
   it(`returns 'kibana_dev' kid for development`, async () => {
@@ -42,9 +35,25 @@ describe('getKID', () => {
 });
 
 describe('encryptTelemetry', () => {
+  afterEach(() => {
+    mockEncrypt.mockReset();
+  });
+
   it('encrypts payload', async () => {
     const payload = { some: 'value' };
-    await encryptTelemetry(payload, true);
+    await encryptTelemetry(payload, { isProd: true });
     expect(createRequestEncryptor).toBeCalledWith(telemetryJWKS);
   });
+
+  it('uses kibana kid on { isProd: true }', async () => {
+    const payload = { some: 'value' };
+    await encryptTelemetry(payload, { isProd: true });
+    expect(mockEncrypt).toBeCalledWith('kibana', payload);
+  });
+
+  it('uses kibana_dev kid on { isProd: false }', async () => {
+    const payload = { some: 'value' };
+    await encryptTelemetry(payload, { isProd: false });
+    expect(mockEncrypt).toBeCalledWith('kibana_dev', payload);
+  });
 });
diff --git a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts
index c20f4b768b7dc..44f053064cfcb 100644
--- a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts
+++ b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts
@@ -24,7 +24,7 @@ export function getKID(isProd = false): string {
   return isProd ? 'kibana' : 'kibana_dev';
 }
 
-export async function encryptTelemetry(payload: any, isProd = false): Promise<string[]> {
+export async function encryptTelemetry(payload: any, { isProd = false } = {}): Promise<string[]> {
   const kid = getKID(isProd);
   const encryptor = await createRequestEncryptor(telemetryJWKS);
   const clusters = [].concat(payload);
diff --git a/src/plugins/telemetry_collection_manager/server/plugin.ts b/src/plugins/telemetry_collection_manager/server/plugin.ts
index 7e8dff9e0aec1..f2f20e215c535 100644
--- a/src/plugins/telemetry_collection_manager/server/plugin.ts
+++ b/src/plugins/telemetry_collection_manager/server/plugin.ts
@@ -158,7 +158,7 @@ export class TelemetryCollectionManagerPlugin
           if (config.unencrypted) {
             return optInStats;
           }
-          return encryptTelemetry(optInStats, this.isDev);
+          return encryptTelemetry(optInStats, { isProd: !this.isDev });
         }
       } catch (err) {
         this.logger.debug(`Failed to collect any opt in stats with registered collections.`);
@@ -205,7 +205,8 @@ export class TelemetryCollectionManagerPlugin
           if (config.unencrypted) {
             return usageData;
           }
-          return encryptTelemetry(usageData, this.isDev);
+
+          return encryptTelemetry(usageData, { isProd: !this.isDev });
         }
       } catch (err) {
         this.logger.debug(
diff --git a/yarn.lock b/yarn.lock
index 11abd95498c8d..42f891aa24e25 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1401,10 +1401,10 @@
   resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.4.0.tgz#883197b7f4bf3c2dd994f53b274769ddfa2bf79a"
   integrity sha512-uGBKGCNghTgUZPHClji/00v+AKt5nidPTGOIbcT+lbTPVxNB6QPpPLGWtXyrg3QZAxobPM/LAZB1mAqtJeq44Q==
 
-"@elastic/request-crypto@1.1.2":
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/@elastic/request-crypto/-/request-crypto-1.1.2.tgz#2e323550f546f6286994126d462a9ea480a3bfb1"
-  integrity sha512-i73wjj1Qi8dGJIy170Z8xyJ760mFNjTbdmcp/nEczqWD0miNW6I5wZ5MNrv7M6CXn2m1wMXiT6qzDYd93Hv1Dw==
+"@elastic/request-crypto@1.1.4":
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/@elastic/request-crypto/-/request-crypto-1.1.4.tgz#2189d5fea65f7afe1de9f5fa3d0dd420e93e3124"
+  integrity sha512-D5CzSGKkM6BdrVB/HRRTheMsNQOcd2FMUup0O/1hIGUBE8zHh2AYbmSNSpD6LyQAgY39mGkARUi/x+SO0ccVvg==
   dependencies:
     "@elastic/node-crypto" "1.1.1"
     "@types/node-jose" "1.1.0"

From eb3fe8eb50be7876128bc592f9ce913259be3ee4 Mon Sep 17 00:00:00 2001
From: Dmitry Lemeshko <dzmitry.lemechko@elastic.co>
Date: Fri, 10 Apr 2020 23:05:20 +0300
Subject: [PATCH 61/78] update chromedriver dependency to 81.0.0 (#63266)

---
 package.json |  2 +-
 yarn.lock    | 38 ++++++++++++++++++++++++++++----------
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/package.json b/package.json
index a5d46e7f2bf40..2bad3116c9ef2 100644
--- a/package.json
+++ b/package.json
@@ -401,7 +401,7 @@
     "chai": "3.5.0",
     "chance": "1.0.18",
     "cheerio": "0.22.0",
-    "chromedriver": "^80.0.1",
+    "chromedriver": "^81.0.0",
     "classnames": "2.2.6",
     "dedent": "^0.7.0",
     "delete-empty": "^2.0.0",
diff --git a/yarn.lock b/yarn.lock
index 42f891aa24e25..8ca25cc18a8a2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5061,6 +5061,13 @@
   dependencies:
     "@types/yargs-parser" "*"
 
+"@types/yauzl@^2.9.1":
+  version "2.9.1"
+  resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af"
+  integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==
+  dependencies:
+    "@types/node" "*"
+
 "@types/zen-observable@^0.8.0":
   version "0.8.0"
   resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d"
@@ -8723,16 +8730,16 @@ chrome-trace-event@^1.0.2:
   dependencies:
     tslib "^1.9.0"
 
-chromedriver@^80.0.1:
-  version "80.0.1"
-  resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-80.0.1.tgz#35c1642e2d864b9e8262f291003e455b0e422917"
-  integrity sha512-VfRtZUpBUIjeypS+xM40+VD9g4Drv7L2VibG/4+0zX3mMx4KayN6gfKETycPfO6JwQXTLSxEr58fRcrsa8r5xQ==
+chromedriver@^81.0.0:
+  version "81.0.0"
+  resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-81.0.0.tgz#690ba333aedf2b4c4933b6590c3242d3e5f28f3c"
+  integrity sha512-BA++IQ7O1FzHmNpzMlOfLiSBvPZ946uuhtJjZHEIr/Gb+Ha9jiuGbHiT45l6O3XGbQ8BAwvbmdisjl4rTxro4A==
   dependencies:
     "@testim/chrome-version" "^1.0.7"
     axios "^0.19.2"
     del "^5.1.0"
-    extract-zip "^1.6.7"
-    mkdirp "^1.0.3"
+    extract-zip "^2.0.0"
+    mkdirp "^1.0.4"
     tcp-port-used "^1.0.1"
 
 ci-info@^1.0.0:
@@ -13161,6 +13168,17 @@ extract-zip@^1.6.6, extract-zip@^1.6.7, extract-zip@^1.7.0:
     mkdirp "^0.5.4"
     yauzl "^2.10.0"
 
+extract-zip@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.0.tgz#f53b71d44f4ff5a4527a2259ade000fb8b303492"
+  integrity sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==
+  dependencies:
+    debug "^4.1.1"
+    get-stream "^5.1.0"
+    yauzl "^2.10.0"
+  optionalDependencies:
+    "@types/yauzl" "^2.9.1"
+
 extsprintf@1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@@ -20622,10 +20640,10 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkd
   dependencies:
     minimist "^1.2.5"
 
-mkdirp@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea"
-  integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==
+mkdirp@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+  integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 
 mocha-junit-reporter@^1.23.1:
   version "1.23.1"

From 6393e08ce3ba7cee6f138f2dac6db3a37f6953dc Mon Sep 17 00:00:00 2001
From: Candace Park <56409205+parkiino@users.noreply.github.com>
Date: Fri, 10 Apr 2020 17:20:40 -0400
Subject: [PATCH 62/78] task/mac-eventing-form (#62999)

adds mac events form for endpoint policy details
Co-authored-by: oatkiller <robert.austin@elastic.co>
---
 .../applications/endpoint/models/policy.ts    |   4 +
 .../endpoint/models/policy_details_config.ts  |  30 +++++
 .../store/policy_details/index.test.ts        |  31 ++++-
 .../endpoint/store/policy_details/reducer.ts  |  12 +-
 .../store/policy_details/selectors.ts         |  30 +++--
 .../public/applications/endpoint/types.ts     |  70 ++++++------
 .../endpoint/view/policy/policy_details.tsx   |   6 +-
 .../policy/policy_forms/eventing/checkbox.tsx |  53 ---------
 .../policy/policy_forms/events/checkbox.tsx   |  49 ++++++++
 .../view/policy/policy_forms/events/index.tsx |   8 ++
 .../view/policy/policy_forms/events/mac.tsx   | 106 ++++++++++++++++++
 .../{eventing => events}/windows.tsx          |  59 +++++-----
 12 files changed, 325 insertions(+), 133 deletions(-)
 delete mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/checkbox.tsx
 create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/checkbox.tsx
 create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/index.tsx
 create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/mac.tsx
 rename x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/{eventing => events}/windows.tsx (61%)

diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/models/policy.ts b/x-pack/plugins/endpoint/public/applications/endpoint/models/policy.ts
index 9ac53f9be609f..30f45e54c2005 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/models/policy.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/models/policy.ts
@@ -42,6 +42,8 @@ export const generatePolicy = (): PolicyConfig => {
     mac: {
       events: {
         process: true,
+        file: true,
+        network: true,
       },
       malware: {
         mode: ProtectionModes.detect,
@@ -67,6 +69,8 @@ export const generatePolicy = (): PolicyConfig => {
     linux: {
       events: {
         process: true,
+        file: true,
+        network: true,
       },
       logging: {
         stdout: 'debug',
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/models/policy_details_config.ts b/x-pack/plugins/endpoint/public/applications/endpoint/models/policy_details_config.ts
index 1145d1d19242a..bf96942e83a91 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/models/policy_details_config.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/models/policy_details_config.ts
@@ -43,3 +43,33 @@ export function clone(policyDetailsConfig: UIPolicyConfig): UIPolicyConfig {
    */
   return clonedConfig as UIPolicyConfig;
 }
+
+/**
+ * Returns value from `configuration`
+ */
+export const getIn = (a: UIPolicyConfig) => <Key extends keyof UIPolicyConfig>(key: Key) => <
+  subKey extends keyof UIPolicyConfig[Key]
+>(
+  subKey: subKey
+) => <LeafKey extends keyof UIPolicyConfig[Key][subKey]>(
+  leafKey: LeafKey
+): UIPolicyConfig[Key][subKey][LeafKey] => {
+  return a[key][subKey][leafKey];
+};
+
+/**
+ * Returns cloned `configuration` with `value` set by the `keyPath`.
+ */
+export const setIn = (a: UIPolicyConfig) => <Key extends keyof UIPolicyConfig>(key: Key) => <
+  subKey extends keyof UIPolicyConfig[Key]
+>(
+  subKey: subKey
+) => <LeafKey extends keyof UIPolicyConfig[Key][subKey]>(leafKey: LeafKey) => <
+  V extends UIPolicyConfig[Key][subKey][LeafKey]
+>(
+  v: V
+): UIPolicyConfig => {
+  const c = clone(a);
+  c[key][subKey][leafKey] = v;
+  return c;
+};
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/index.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/index.test.ts
index cf14092953227..e09a62b235e35 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/index.test.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/index.test.ts
@@ -7,7 +7,7 @@
 import { PolicyDetailsState } from '../../types';
 import { createStore, Dispatch, Store } from 'redux';
 import { policyDetailsReducer, PolicyDetailsAction } from './index';
-import { policyConfig, windowsEventing } from './selectors';
+import { policyConfig } from './selectors';
 import { clone } from '../../models/policy_details_config';
 import { generatePolicy } from '../../models/policy';
 
@@ -55,7 +55,7 @@ describe('policy details: ', () => {
     });
   });
 
-  describe('when the user has enabled windows process eventing', () => {
+  describe('when the user has enabled windows process events', () => {
     beforeEach(() => {
       const config = policyConfig(getState());
       if (!config) {
@@ -71,8 +71,31 @@ describe('policy details: ', () => {
       });
     });
 
-    it('windows process eventing is enabled', async () => {
-      expect(windowsEventing(getState())!.process).toEqual(true);
+    it('windows process events is enabled', () => {
+      const config = policyConfig(getState());
+      expect(config!.windows.events.process).toEqual(true);
+    });
+  });
+
+  describe('when the user has enabled mac file events', () => {
+    beforeEach(() => {
+      const config = policyConfig(getState());
+      if (!config) {
+        throw new Error();
+      }
+
+      const newPayload1 = clone(config);
+      newPayload1.mac.events.file = true;
+
+      dispatch({
+        type: 'userChangedPolicyConfig',
+        payload: { policyConfig: newPayload1 },
+      });
+    });
+
+    it('mac file events is enabled', () => {
+      const config = policyConfig(getState());
+      expect(config!.mac.events.file).toEqual(true);
     });
   });
 });
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/reducer.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/reducer.ts
index fb3e26157ef32..fb0f371cdae0d 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/reducer.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/reducer.ts
@@ -5,7 +5,7 @@
  */
 
 import { Reducer } from 'redux';
-import { PolicyData, PolicyDetailsState, UIPolicyConfig } from '../../types';
+import { PolicyDetailsState, UIPolicyConfig } from '../../types';
 import { AppAction } from '../action';
 import { fullPolicy, isOnPolicyDetailsPage } from './selectors';
 
@@ -89,10 +89,12 @@ export const policyDetailsReducer: Reducer<PolicyDetailsState, AppAction> = (
   }
 
   if (action.type === 'userChangedPolicyConfig') {
-    const newState = { ...state, policyItem: { ...(state.policyItem as PolicyData) } };
-    const newPolicy = (newState.policyItem.inputs[0].config.policy.value = {
-      ...fullPolicy(state),
-    });
+    if (!state.policyItem) {
+      return state;
+    }
+    const newState = { ...state, policyItem: { ...state.policyItem } };
+    const newPolicy: any = { ...fullPolicy(state) };
+    newState.policyItem.inputs[0].config.policy.value = newPolicy;
 
     Object.entries(action.payload.policyConfig).forEach(([section, newSettings]) => {
       newPolicy[section as keyof UIPolicyConfig] = {
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/selectors.ts
index 0d505931c9ec5..4b4dc9d9bee43 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/selectors.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/selectors.ts
@@ -79,14 +79,8 @@ export const policyConfig: (s: PolicyDetailsState) => UIPolicyConfig = createSel
   }
 );
 
-/** Returns an object of all the windows eventing configuration */
-export const windowsEventing = (state: PolicyDetailsState) => {
-  const config = policyConfig(state);
-  return config && config.windows.events;
-};
-
 /** Returns the total number of possible windows eventing configurations */
-export const totalWindowsEventing = (state: PolicyDetailsState): number => {
+export const totalWindowsEvents = (state: PolicyDetailsState): number => {
   const config = policyConfig(state);
   if (config) {
     return Object.keys(config.windows.events).length;
@@ -95,7 +89,7 @@ export const totalWindowsEventing = (state: PolicyDetailsState): number => {
 };
 
 /** Returns the number of selected windows eventing configurations */
-export const selectedWindowsEventing = (state: PolicyDetailsState): number => {
+export const selectedWindowsEvents = (state: PolicyDetailsState): number => {
   const config = policyConfig(state);
   if (config) {
     return Object.values(config.windows.events).reduce((count, event) => {
@@ -105,6 +99,26 @@ export const selectedWindowsEventing = (state: PolicyDetailsState): number => {
   return 0;
 };
 
+/** Returns the total number of possible mac eventing configurations */
+export const totalMacEvents = (state: PolicyDetailsState): number => {
+  const config = policyConfig(state);
+  if (config) {
+    return Object.keys(config.mac.events).length;
+  }
+  return 0;
+};
+
+/** Returns the number of selected mac eventing configurations */
+export const selectedMacEvents = (state: PolicyDetailsState): number => {
+  const config = policyConfig(state);
+  if (config) {
+    return Object.values(config.mac.events).reduce((count, event) => {
+      return event === true ? count + 1 : count;
+    }, 0);
+  }
+  return 0;
+};
+
 /** is there an api call in flight */
 export const isLoading = (state: PolicyDetailsState) => state.isLoading;
 
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts
index d4f6d2457254e..dda50847169e7 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts
@@ -118,34 +118,21 @@ export interface PolicyDetailsState {
  * Endpoint Policy configuration
  */
 export interface PolicyConfig {
-  windows: {
-    events: {
-      process: boolean;
-      network: boolean;
-    };
-    /** malware mode can be off, detect, prevent or prevent and notify user */
-    malware: MalwareFields;
+  windows: UIPolicyConfig['windows'] & {
     logging: {
       stdout: string;
       file: string;
     };
     advanced: PolicyConfigAdvancedOptions;
   };
-  mac: {
-    events: {
-      process: boolean;
-    };
-    malware: MalwareFields;
+  mac: UIPolicyConfig['mac'] & {
     logging: {
       stdout: string;
       file: string;
     };
     advanced: PolicyConfigAdvancedOptions;
   };
-  linux: {
-    events: {
-      process: boolean;
-    };
+  linux: UIPolicyConfig['linux'] & {
     logging: {
       stdout: string;
       file: string;
@@ -168,29 +155,39 @@ interface PolicyConfigAdvancedOptions {
   };
 }
 
-/**
- * Windows-specific policy configuration that is supported via the UI
- */
-type WindowsPolicyConfig = Pick<PolicyConfig['windows'], 'events' | 'malware'>;
-
-/**
- * Mac-specific policy configuration that is supported via the UI
- */
-type MacPolicyConfig = Pick<PolicyConfig['mac'], 'malware' | 'events'>;
-
-/**
- * Linux-specific policy configuration that is supported via the UI
- */
-type LinuxPolicyConfig = Pick<PolicyConfig['linux'], 'events'>;
-
 /**
  * The set of Policy configuration settings that are show/edited via the UI
  */
-export interface UIPolicyConfig {
-  windows: WindowsPolicyConfig;
-  mac: MacPolicyConfig;
-  linux: LinuxPolicyConfig;
-}
+/* eslint-disable @typescript-eslint/consistent-type-definitions */
+export type UIPolicyConfig = {
+  windows: {
+    events: {
+      process: boolean;
+      network: boolean;
+    };
+    /** malware mode can be off, detect, prevent or prevent and notify user */
+    malware: MalwareFields;
+  };
+  mac: {
+    events: {
+      file: boolean;
+      process: boolean;
+      network: boolean;
+    };
+    malware: MalwareFields;
+  };
+
+  /**
+   * Linux-specific policy configuration that is supported via the UI
+   */
+  linux: {
+    events: {
+      file: boolean;
+      process: boolean;
+      network: boolean;
+    };
+  };
+};
 
 /** OS used in Policy */
 export enum OS {
@@ -203,6 +200,7 @@ export enum OS {
 export enum EventingFields {
   process = 'process',
   network = 'network',
+  file = 'file',
 }
 
 /**
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx
index bc56e5e6f6329..1e723e32615eb 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx
@@ -29,12 +29,12 @@ import {
   isLoading,
   apiError,
 } from '../../store/policy_details/selectors';
-import { WindowsEventing } from './policy_forms/eventing/windows';
 import { PageView, PageViewHeaderTitle } from '../../components/page_view';
 import { AppAction } from '../../types';
 import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
 import { AgentsSummary } from './agents_summary';
 import { VerticalDivider } from './vertical_divider';
+import { WindowsEvents, MacEvents } from './policy_forms/events';
 import { MalwareProtections } from './policy_forms/protections/malware';
 
 export const PolicyDetails = React.memo(() => {
@@ -206,7 +206,9 @@ export const PolicyDetails = React.memo(() => {
           </h4>
         </EuiText>
         <EuiSpacer size="xs" />
-        <WindowsEventing />
+        <WindowsEvents />
+        <EuiSpacer size="l" />
+        <MacEvents />
       </PageView>
     </>
   );
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/checkbox.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/checkbox.tsx
deleted file mode 100644
index 8b7fb89ed1646..0000000000000
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/checkbox.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React, { useCallback } from 'react';
-import { EuiCheckbox } from '@elastic/eui';
-import { useDispatch } from 'react-redux';
-import { usePolicyDetailsSelector } from '../../policy_hooks';
-import { policyConfig, windowsEventing } from '../../../../store/policy_details/selectors';
-import { PolicyDetailsAction } from '../../../../store/policy_details';
-import { OS, EventingFields } from '../../../../types';
-import { clone } from '../../../../models/policy_details_config';
-
-export const EventingCheckbox: React.FC<{
-  id: string;
-  name: string;
-  os: OS;
-  protectionField: EventingFields;
-}> = React.memo(({ id, name, os, protectionField }) => {
-  const policyDetailsConfig = usePolicyDetailsSelector(policyConfig);
-  const eventing = usePolicyDetailsSelector(windowsEventing);
-  const dispatch = useDispatch<(action: PolicyDetailsAction) => void>();
-
-  const handleRadioChange = useCallback(
-    (event: React.ChangeEvent<HTMLInputElement>) => {
-      if (policyDetailsConfig) {
-        const newPayload = clone(policyDetailsConfig);
-        if (os === OS.linux || os === OS.mac) {
-          newPayload[os].events.process = event.target.checked;
-        } else {
-          newPayload[os].events[protectionField] = event.target.checked;
-        }
-
-        dispatch({
-          type: 'userChangedPolicyConfig',
-          payload: { policyConfig: newPayload },
-        });
-      }
-    },
-    [dispatch, os, policyDetailsConfig, protectionField]
-  );
-
-  return (
-    <EuiCheckbox
-      id={id}
-      label={name}
-      checked={eventing && eventing[protectionField]}
-      onChange={handleRadioChange}
-    />
-  );
-});
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/checkbox.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/checkbox.tsx
new file mode 100644
index 0000000000000..bec6b33b85c7f
--- /dev/null
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/checkbox.tsx
@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useCallback, useMemo } from 'react';
+import { EuiCheckbox } from '@elastic/eui';
+import { useDispatch } from 'react-redux';
+import { htmlIdGenerator } from '@elastic/eui';
+import { usePolicyDetailsSelector } from '../../policy_hooks';
+import { policyConfig } from '../../../../store/policy_details/selectors';
+import { PolicyDetailsAction } from '../../../../store/policy_details';
+import { UIPolicyConfig } from '../../../../types';
+
+export const EventsCheckbox = React.memo(function({
+  name,
+  setter,
+  getter,
+}: {
+  name: string;
+  setter: (config: UIPolicyConfig, checked: boolean) => UIPolicyConfig;
+  getter: (config: UIPolicyConfig) => boolean;
+}) {
+  const policyDetailsConfig = usePolicyDetailsSelector(policyConfig);
+  const selected = getter(policyDetailsConfig);
+  const dispatch = useDispatch<(action: PolicyDetailsAction) => void>();
+
+  const handleCheckboxChange = useCallback(
+    (event: React.ChangeEvent<HTMLInputElement>) => {
+      if (policyDetailsConfig) {
+        dispatch({
+          type: 'userChangedPolicyConfig',
+          payload: { policyConfig: setter(policyDetailsConfig, event.target.checked) },
+        });
+      }
+    },
+    [dispatch, policyDetailsConfig, setter]
+  );
+
+  return (
+    <EuiCheckbox
+      id={useMemo(() => htmlIdGenerator()(), [])}
+      label={name}
+      checked={selected}
+      onChange={handleCheckboxChange}
+    />
+  );
+});
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/index.tsx
new file mode 100644
index 0000000000000..44716d8183041
--- /dev/null
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/index.tsx
@@ -0,0 +1,8 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { WindowsEvents } from './windows';
+export { MacEvents } from './mac';
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/mac.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/mac.tsx
new file mode 100644
index 0000000000000..3b69c21d2b150
--- /dev/null
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/mac.tsx
@@ -0,0 +1,106 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useMemo } from 'react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { EuiTitle, EuiText, EuiSpacer } from '@elastic/eui';
+import { EventsCheckbox } from './checkbox';
+import { OS, UIPolicyConfig } from '../../../../types';
+import { usePolicyDetailsSelector } from '../../policy_hooks';
+import { selectedMacEvents, totalMacEvents } from '../../../../store/policy_details/selectors';
+import { ConfigForm } from '../config_form';
+import { getIn, setIn } from '../../../../models/policy_details_config';
+
+export const MacEvents = React.memo(() => {
+  const selected = usePolicyDetailsSelector(selectedMacEvents);
+  const total = usePolicyDetailsSelector(totalMacEvents);
+
+  const checkboxes: Array<{
+    name: string;
+    os: 'mac';
+    protectionField: keyof UIPolicyConfig['mac']['events'];
+  }> = useMemo(
+    () => [
+      {
+        name: i18n.translate('xpack.endpoint.policyDetailsConfig.mac.events.file', {
+          defaultMessage: 'File',
+        }),
+        os: OS.mac,
+        protectionField: 'file',
+      },
+      {
+        name: i18n.translate('xpack.endpoint.policyDetailsConfig.mac.events.process', {
+          defaultMessage: 'Process',
+        }),
+        os: OS.mac,
+        protectionField: 'process',
+      },
+      {
+        name: i18n.translate('xpack.endpoint.policyDetailsConfig.mac.events.network', {
+          defaultMessage: 'Network',
+        }),
+        os: OS.mac,
+        protectionField: 'network',
+      },
+    ],
+    []
+  );
+
+  const renderCheckboxes = () => {
+    return (
+      <>
+        <EuiTitle size="xxs">
+          <h5>
+            <FormattedMessage
+              id="xpack.endpoint.policyDetailsConfig.eventingEvents"
+              defaultMessage="Events"
+            />
+          </h5>
+        </EuiTitle>
+        <EuiSpacer size="s" />
+        {checkboxes.map((item, index) => {
+          return (
+            <EventsCheckbox
+              name={item.name}
+              key={index}
+              setter={(config, checked) =>
+                setIn(config)(item.os)('events')(item.protectionField)(checked)
+              }
+              getter={config => getIn(config)(item.os)('events')(item.protectionField)}
+            />
+          );
+        })}
+      </>
+    );
+  };
+
+  const collectionsEnabled = () => {
+    return (
+      <EuiText size="s" color="subdued">
+        <FormattedMessage
+          id="xpack.endpoint.policy.details.eventCollectionsEnabled"
+          defaultMessage="{selected} / {total} event collections enabled"
+          values={{ selected, total }}
+        />
+      </EuiText>
+    );
+  };
+
+  return (
+    <ConfigForm
+      type={i18n.translate('xpack.endpoint.policy.details.eventCollection', {
+        defaultMessage: 'Event Collection',
+      })}
+      supportedOss={[
+        i18n.translate('xpack.endpoint.policy.details.mac', { defaultMessage: 'Mac' }),
+      ]}
+      id="macEventingForm"
+      rightCorner={collectionsEnabled()}
+      children={renderCheckboxes()}
+    />
+  );
+});
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/windows.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/windows.tsx
similarity index 61%
rename from x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/windows.tsx
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/windows.tsx
index 7bec2c4c742d2..63a140912437d 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/eventing/windows.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_forms/events/windows.tsx
@@ -8,40 +8,45 @@ import React, { useMemo } from 'react';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { EuiTitle, EuiText, EuiSpacer } from '@elastic/eui';
-import { EventingCheckbox } from './checkbox';
-import { OS, EventingFields } from '../../../../types';
+import { EventsCheckbox } from './checkbox';
+import { OS, UIPolicyConfig } from '../../../../types';
 import { usePolicyDetailsSelector } from '../../policy_hooks';
 import {
-  selectedWindowsEventing,
-  totalWindowsEventing,
+  selectedWindowsEvents,
+  totalWindowsEvents,
 } from '../../../../store/policy_details/selectors';
 import { ConfigForm } from '../config_form';
+import { setIn, getIn } from '../../../../models/policy_details_config';
 
-export const WindowsEventing = React.memo(() => {
-  const selected = usePolicyDetailsSelector(selectedWindowsEventing);
-  const total = usePolicyDetailsSelector(totalWindowsEventing);
+export const WindowsEvents = React.memo(() => {
+  const selected = usePolicyDetailsSelector(selectedWindowsEvents);
+  const total = usePolicyDetailsSelector(totalWindowsEvents);
 
-  const checkboxes = useMemo(
+  const checkboxes: Array<{
+    name: string;
+    os: 'windows';
+    protectionField: keyof UIPolicyConfig['windows']['events'];
+  }> = useMemo(
     () => [
       {
-        name: i18n.translate('xpack.endpoint.policyDetailsConfig.eventingProcess', {
+        name: i18n.translate('xpack.endpoint.policyDetailsConfig.windows.events.process', {
           defaultMessage: 'Process',
         }),
         os: OS.windows,
-        protectionField: EventingFields.process,
+        protectionField: 'process',
       },
       {
-        name: i18n.translate('xpack.endpoint.policyDetailsConfig.eventingNetwork', {
+        name: i18n.translate('xpack.endpoint.policyDetailsConfig.windows.events.network', {
           defaultMessage: 'Network',
         }),
         os: OS.windows,
-        protectionField: EventingFields.network,
+        protectionField: 'network',
       },
     ],
     []
   );
 
-  const renderCheckboxes = () => {
+  const renderCheckboxes = useMemo(() => {
     return (
       <>
         <EuiTitle size="xxs">
@@ -55,20 +60,21 @@ export const WindowsEventing = React.memo(() => {
         <EuiSpacer size="s" />
         {checkboxes.map((item, index) => {
           return (
-            <EventingCheckbox
-              id={`eventing${item.name}`}
+            <EventsCheckbox
               name={item.name}
               key={index}
-              os={item.os}
-              protectionField={item.protectionField}
+              setter={(config, checked) =>
+                setIn(config)(item.os)('events')(item.protectionField)(checked)
+              }
+              getter={config => getIn(config)(item.os)('events')(item.protectionField)}
             />
           );
         })}
       </>
     );
-  };
+  }, [checkboxes]);
 
-  const collectionsEnabled = () => {
+  const collectionsEnabled = useMemo(() => {
     return (
       <EuiText size="s" color="subdued">
         <FormattedMessage
@@ -78,19 +84,22 @@ export const WindowsEventing = React.memo(() => {
         />
       </EuiText>
     );
-  };
+  }, [selected, total]);
 
   return (
     <ConfigForm
       type={i18n.translate('xpack.endpoint.policy.details.eventCollection', {
         defaultMessage: 'Event Collection',
       })}
-      supportedOss={[
-        i18n.translate('xpack.endpoint.policy.details.windows', { defaultMessage: 'Windows' }),
-      ]}
+      supportedOss={useMemo(
+        () => [
+          i18n.translate('xpack.endpoint.policy.details.windows', { defaultMessage: 'Windows' }),
+        ],
+        []
+      )}
       id="windowsEventingForm"
-      rightCorner={collectionsEnabled()}
-      children={renderCheckboxes()}
+      rightCorner={collectionsEnabled}
+      children={renderCheckboxes}
     />
   );
 });

From 39fbc5e103a50a2d9ef929b05696d478c1090269 Mon Sep 17 00:00:00 2001
From: The SpaceCake Project <randomuserid@users.noreply.github.com>
Date: Fri, 10 Apr 2020 17:50:23 -0400
Subject: [PATCH 63/78] bc6 rule import april 9 (#63152)

* bc6 rule import april 9

Increased the lookback of the ML rules

* re-import

with LF chars

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../prepackaged_rules/linux_anomalous_network_activity.json     | 2 +-
 .../linux_anomalous_network_port_activity.json                  | 2 +-
 .../prepackaged_rules/linux_anomalous_network_service.json      | 2 +-
 .../prepackaged_rules/linux_anomalous_network_url_activity.json | 2 +-
 .../prepackaged_rules/linux_anomalous_process_all_hosts.json    | 2 +-
 .../rules/prepackaged_rules/linux_anomalous_user_name.json      | 2 +-
 .../rules/prepackaged_rules/packetbeat_dns_tunneling.json       | 2 +-
 .../rules/prepackaged_rules/packetbeat_rare_dns_question.json   | 2 +-
 .../rules/prepackaged_rules/packetbeat_rare_server_domain.json  | 2 +-
 .../rules/prepackaged_rules/packetbeat_rare_urls.json           | 2 +-
 .../rules/prepackaged_rules/packetbeat_rare_user_agent.json     | 2 +-
 .../rules/prepackaged_rules/rare_process_by_host_linux.json     | 2 +-
 .../rules/prepackaged_rules/rare_process_by_host_windows.json   | 2 +-
 .../rules/prepackaged_rules/suspicious_login_activity.json      | 2 +-
 .../prepackaged_rules/windows_anomalous_network_activity.json   | 2 +-
 .../prepackaged_rules/windows_anomalous_path_activity.json      | 2 +-
 .../prepackaged_rules/windows_anomalous_process_all_hosts.json  | 2 +-
 .../prepackaged_rules/windows_anomalous_process_creation.json   | 2 +-
 .../rules/prepackaged_rules/windows_anomalous_script.json       | 2 +-
 .../rules/prepackaged_rules/windows_anomalous_service.json      | 2 +-
 .../rules/prepackaged_rules/windows_anomalous_user_name.json    | 2 +-
 .../rules/prepackaged_rules/windows_rare_user_runas_event.json  | 2 +-
 .../windows_rare_user_type10_remote_login.json                  | 2 +-
 23 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json
index 1123c1161c4ce..fe248a6c1e23e 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that rarely uses the network could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "linux_anomalous_network_activity_ecs",
   "name": "Unusual Linux Network Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_port_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_port_activity.json
index 19dd643945b17..d435d4c10f05c 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_port_activity.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_port_activity.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that rarely uses the network could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "linux_anomalous_network_port_activity_ecs",
   "name": "Unusual Linux Network Port Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_service.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_service.json
index e2e5803618d06..0b82ce99d0b7f 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_service.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_service.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that rarely uses the network could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "linux_anomalous_network_service",
   "name": "Unusual Linux Network Service",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_url_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_url_activity.json
index 40dd2e76c7214..26af34e18a4c8 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_url_activity.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_url_activity.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A new and unusual program or artifact download in the course of software upgrades, debugging, or troubleshooting could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "linux_anomalous_network_url_activity_ecs",
   "name": "Unusual Linux Web Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json
index 6bac2f25fd7de..d15c4fc794378 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "linux_anomalous_process_all_hosts_ecs",
   "name": "Anomalous Process For a Linux Population",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json
index 8b7e6c89482f7..2f33948b0a93e 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Uncommon user activity can be due to an engineer logging onto a server instance in order to perform manual troubleshooting or reconfiguration."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "linux_anomalous_user_name_ecs",
   "name": "Unusual Linux Username",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_dns_tunneling.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_dns_tunneling.json
index c70725dcb645a..765515ffda27c 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_dns_tunneling.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_dns_tunneling.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "DNS domains that use large numbers of child domains, such as software or content distribution networks, can trigger this signal and such parent domains can be excluded."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "packetbeat_dns_tunneling",
   "name": "DNS Tunneling",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_dns_question.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_dns_question.json
index 3ed40ddf27864..79c30c5b38378 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_dns_question.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_dns_question.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal. Network activity that occurs rarely, in small quantities, can trigger this signal. Possible examples are browsing technical support or vendor networks sparsely. A user who visits a new or unique web destination may trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "packetbeat_rare_dns_question",
   "name": "Unusual DNS Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_server_domain.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_server_domain.json
index c49bc95be75d2..7b14ad62f6c93 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_server_domain.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_server_domain.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Web activity that occurs rarely in small quantities can trigger this signal. Possible examples are browsing technical support or vendor URLs that are used very sparsely. A user who visits a new and unique web destination may trigger this signal when the activity is sparse. Web applications that generate URLs unique to a transaction may trigger this when they are used sparsely. Web domains can be excluded in cases such as these."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "packetbeat_rare_server_domain",
   "name": "Unusual Network Destination Domain Name",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_urls.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_urls.json
index 02a4a5f729a16..76767545e794a 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_urls.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_urls.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Web activity that occurs rarely in small quantities can trigger this signal. Possible examples are browsing technical support or vendor URLs that are used very sparsely. A user who visits a new and unique web destination may trigger this signal when the activity is sparse. Web applications that generate URLs unique to a transaction may trigger this when they are used sparsely. Web domains can be excluded in cases such as these."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "packetbeat_rare_urls",
   "name": "Unusual Web Request",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_user_agent.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_user_agent.json
index 76ed6b263a704..1dc49203f31c1 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_user_agent.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/packetbeat_rare_user_agent.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Web activity that is uncommon, like security scans, may trigger this signal and may need to be excluded. A new or rarely used program that calls web services may trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "packetbeat_rare_user_agent",
   "name": "Unusual Web User Agent",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json
index 048f93e170656..f071677ae8d33 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "rare_process_by_host_linux_ecs",
   "name": "Unusual Process For a Linux Host",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json
index 7bc46cdc04dd2..5e0050c6c25ec 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "rare_process_by_host_windows_ecs",
   "name": "Unusual Process For a Windows Host",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_login_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_login_activity.json
index 915bc1bcfc051..4b94fdc6da147 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_login_activity.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_login_activity.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Security audits may trigger this signal. Conditions that generate bursts of failed logins, such as misconfigured applications or account lockouts could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "suspicious_login_activity_ecs",
   "name": "Unusual Login Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json
index 72671760c9c8d..ca18fe95b1fc1 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that rarely uses the network could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_network_activity_ecs",
   "name": "Unusual Windows Network Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_path_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_path_activity.json
index 082fce438ca9e..8a88607b9d5c9 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_path_activity.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_path_activity.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A new and unusual program or artifact download in the course of software upgrades, debugging, or troubleshooting could trigger this signal. Users downloading and running programs from unusual locations, such as temporary directories, browser caches, or profile paths could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_path_activity_ecs",
   "name": "Unusual Windows Path Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json
index 93469b5a06223..1229c4a52b97d 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_process_all_hosts_ecs",
   "name": "Anomalous Process For a Windows Population",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_creation.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_creation.json
index 1b80e443baae6..98a078ccea4a4 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_creation.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_creation.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Users running scripts in the course of technical support operations of software upgrades could trigger this signal. A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_process_creation",
   "name": "Anomalous Windows Process Creation",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_script.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_script.json
index 4de5443bcaf3f..564ca1782526f 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_script.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_script.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Certain kinds of security testing may trigger this signal. PowerShell scripts that use high levels of obfuscation or have unusual script block payloads may trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_script",
   "name": "Suspicious Powershell Script",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_service.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_service.json
index 7e0641fee68c2..afef569f4ebb4 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_service.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_service.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this signal."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_service",
   "name": "Unusual Windows Service",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json
index 217404b6eb474..703dc1a1dc633 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Uncommon user activity can be due to an administrator or help desk technician logging onto a workstation or server in order to perform manual troubleshooting or reconfiguration."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_anomalous_user_name_ecs",
   "name": "Unusual Windows Username",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_runas_event.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_runas_event.json
index 3dca119b5a28e..febaa57443f76 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_runas_event.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_runas_event.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Uncommon user privilege elevation activity can be due to an administrator, help desk technician, or a user performing manual troubleshooting or reconfiguration."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_rare_user_runas_event",
   "name": "Unusual Windows User Privilege Elevation Activity",
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json
index 09ff2a0cedf41..946cdb95b8e70 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json
@@ -4,7 +4,7 @@
   "false_positives": [
     "Uncommon username activity can be due to an engineer logging onto a server instance in order to perform manual troubleshooting or reconfiguration."
   ],
-  "from": "now-16m",
+  "from": "now-45m",
   "interval": "15m",
   "machine_learning_job_id": "windows_rare_user_type10_remote_login",
   "name": "Unusual Windows Remote User",

From fbd15ec8675029a398381ef063fa8a817e21146c Mon Sep 17 00:00:00 2001
From: Yuliia Naumenko <jo.naumenko@gmail.com>
Date: Fri, 10 Apr 2020 14:55:03 -0700
Subject: [PATCH 64/78] Added UI for pre-configured connectors. (#63074)

* Added UI for pre-configured connectors.

* fixed due to comments

* Fixed jest tests

* Fixed due to comments and added some functional tests

* test fix

* Fixed failed checks

* Fixed functional tests failing
---
 .../translations/translations/ja-JP.json      |   1 -
 .../translations/translations/zh-CN.json      |   1 -
 .../components/add_message_variables.tsx      |   3 +-
 .../action_connector_form/action_form.tsx     |  15 +-
 .../connector_edit_flyout.test.tsx            |  56 +++++++
 .../connector_edit_flyout.tsx                 | 137 +++++++++++++-----
 .../actions_connectors_list.test.tsx          |  16 +-
 .../components/actions_connectors_list.tsx    |  78 +++++++---
 .../apps/triggers_actions_ui/alerts.ts        |  22 ++-
 .../apps/triggers_actions_ui/connectors.ts    |  25 ++++
 x-pack/test/functional_with_es_ssl/config.ts  |  10 ++
 11 files changed, 286 insertions(+), 78 deletions(-)

diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 09903c34e2e5e..fe0c58e83e544 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -16102,7 +16102,6 @@
     "xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.userTextFieldLabel": "ユーザー名",
     "xpack.triggersActionsUI.sections.editConnectorForm.betaBadgeTooltipContent": "{pluginName} はベータ段階で、変更される可能性があります。デザインとコードはオフィシャル GA 機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャル GA 機能の SLA が適用されません。",
     "xpack.triggersActionsUI.sections.editConnectorForm.cancelButtonLabel": "キャンセル",
-    "xpack.triggersActionsUI.sections.editConnectorForm.flyoutTitle": "コネクターを編集",
     "xpack.triggersActionsUI.sections.editConnectorForm.saveButtonLabel": "保存",
     "xpack.triggersActionsUI.sections.editConnectorForm.updateErrorNotificationText": "コネクターを更新できません。",
     "xpack.triggersActionsUI.sections.editConnectorForm.updateSuccessNotificationText": "「{connectorName}」を更新しました",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index cc1b7d7980a0b..fd2a92c2c402f 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -16107,7 +16107,6 @@
     "xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.userTextFieldLabel": "用户名",
     "xpack.triggersActionsUI.sections.editConnectorForm.betaBadgeTooltipContent": "{pluginName} 为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束。",
     "xpack.triggersActionsUI.sections.editConnectorForm.cancelButtonLabel": "取消",
-    "xpack.triggersActionsUI.sections.editConnectorForm.flyoutTitle": "编辑连接器",
     "xpack.triggersActionsUI.sections.editConnectorForm.saveButtonLabel": "保存",
     "xpack.triggersActionsUI.sections.editConnectorForm.updateErrorNotificationText": "无法更新连接器。",
     "xpack.triggersActionsUI.sections.editConnectorForm.updateSuccessNotificationText": "已更新“{connectorName}”",
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx
index ab9b5c2586c17..957c79a5c5123 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx
@@ -22,9 +22,10 @@ export const AddMessageVariables: React.FunctionComponent<Props> = ({
   const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState<boolean>(false);
 
   const getMessageVariables = () =>
-    messageVariables?.map((variable: string) => (
+    messageVariables?.map((variable: string, i: number) => (
       <EuiContextMenuItem
         key={variable}
+        data-test-subj={`variableMenuButton-${i}`}
         icon="empty"
         onClick={() => {
           onSelectEventHandler(variable);
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx
index 6b011ac84bc6f..5890d9fe07f0e 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx
@@ -141,15 +141,22 @@ export const ActionForm = ({
       });
     }
   }
+  const preconfiguredMessage = i18n.translate(
+    'xpack.triggersActionsUI.sections.actionForm.preconfiguredTitleMessage',
+    {
+      defaultMessage: '(pre-configured)',
+    }
+  );
   const getSelectedOptions = (actionItemId: string) => {
     const val = connectors.find(connector => connector.id === actionItemId);
     if (!val) {
       return [];
     }
+    const optionTitle = `${val.name} ${val.isPreconfigured ? preconfiguredMessage : ''}`;
     return [
       {
-        label: val.name,
-        value: val.name,
+        label: optionTitle,
+        value: optionTitle,
         id: actionItemId,
       },
     ];
@@ -264,7 +271,9 @@ export const ActionForm = ({
                         defaultMessage="{actionConnectorName}"
                         id="xpack.triggersActionsUI.sections.alertForm.selectAlertActionTypeEditTitle"
                         values={{
-                          actionConnectorName: actionConnector.name,
+                          actionConnectorName: `${actionConnector.name} ${
+                            actionConnector.isPreconfigured ? preconfiguredMessage : ''
+                          }`,
                         }}
                       />
                     </EuiFlexItem>
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx
index 2c063ea6b4fa6..6659888797679 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx
@@ -95,4 +95,60 @@ describe('connector_edit_flyout', () => {
     expect(connectorNameField.exists()).toBeTruthy();
     expect(connectorNameField.first().prop('value')).toBe('action-connector');
   });
+
+  test('if pre-configured connector rendered correct in the edit form', () => {
+    const connector = {
+      secrets: {},
+      id: 'test',
+      actionTypeId: 'test-action-type-id',
+      actionType: 'test-action-type-name',
+      name: 'pre-configured-connector',
+      isPreconfigured: true,
+      referencedByCount: 0,
+      config: {},
+    };
+
+    const actionType = {
+      id: 'test-action-type-id',
+      iconClass: 'test',
+      selectMessage: 'test',
+      validateConnector: (): ValidationResult => {
+        return { errors: {} };
+      },
+      validateParams: (): ValidationResult => {
+        const validationResult = { errors: {} };
+        return validationResult;
+      },
+      actionConnectorFields: null,
+      actionParamsFields: null,
+    };
+    actionTypeRegistry.get.mockReturnValue(actionType);
+    actionTypeRegistry.has.mockReturnValue(true);
+
+    const wrapper = mountWithIntl(
+      <AppContextProvider appDeps={deps}>
+        <ActionsConnectorsContextProvider
+          value={{
+            http: deps.http,
+            toastNotifications: deps.toastNotifications,
+            capabilities: deps.capabilities,
+            actionTypeRegistry: deps.actionTypeRegistry,
+            reloadConnectors: () => {
+              return new Promise<void>(() => {});
+            },
+          }}
+        >
+          <ConnectorEditFlyout
+            initialConnector={connector}
+            editFlyoutVisible={true}
+            setEditFlyoutVisibility={state => {}}
+          />
+        </ActionsConnectorsContextProvider>
+      </AppContextProvider>
+    );
+
+    const preconfiguredBadge = wrapper.find('[data-test-subj="preconfiguredBadge"]');
+    expect(preconfiguredBadge.exists()).toBeTruthy();
+    expect(wrapper.find('[data-test-subj="saveEditedActionButton"]').exists()).toBeFalsy();
+  });
 });
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx
index ed8811d26331b..a81d6c285f460 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx
@@ -3,7 +3,7 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React, { useCallback, useReducer, useState } from 'react';
+import React, { useCallback, useReducer, useState, Fragment } from 'react';
 import { FormattedMessage } from '@kbn/i18n/react';
 import {
   EuiTitle,
@@ -17,6 +17,8 @@ import {
   EuiButtonEmpty,
   EuiButton,
   EuiBetaBadge,
+  EuiText,
+  EuiLink,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { ActionConnectorForm, validateBaseProperties } from './action_connector_form';
@@ -91,8 +93,77 @@ export const ConnectorEditFlyout = ({
         return undefined;
       });
 
+  const flyoutTitle = connector.isPreconfigured ? (
+    <Fragment>
+      <EuiTitle size="s">
+        <h3 id="flyoutTitle">
+          <FormattedMessage
+            defaultMessage="{connectorName}"
+            id="xpack.triggersActionsUI.sections.preconfiguredConnectorForm.flyoutTitle"
+            values={{ connectorName: initialConnector.name }}
+          />
+          &emsp;
+          <EuiBetaBadge
+            label="Pre-configured"
+            data-test-subj="preconfiguredBadge"
+            tooltipContent={i18n.translate(
+              'xpack.triggersActionsUI.sections.preconfiguredConnectorForm.tooltipContent',
+              {
+                defaultMessage: 'This connector is preconfigured and cannot be edited',
+              }
+            )}
+          />
+          &emsp;
+          <EuiBetaBadge
+            label="Beta"
+            tooltipContent={i18n.translate(
+              'xpack.triggersActionsUI.sections.preconfiguredConnectorForm.betaBadgeTooltipContent',
+              {
+                defaultMessage:
+                  '{pluginName} is in beta and is subject to change. The design and code is less mature than official GA features and is being provided as-is with no warranties. Beta features are not subject to the support SLA of official GA features.',
+                values: {
+                  pluginName: PLUGIN.getI18nName(i18n),
+                },
+              }
+            )}
+          />
+        </h3>
+      </EuiTitle>
+      <EuiText size="s">
+        <FormattedMessage
+          defaultMessage="{actionDescription}"
+          id="xpack.triggersActionsUI.sections.editConnectorForm.actionTypeDescription"
+          values={{ actionDescription: actionTypeModel.selectMessage }}
+        />
+      </EuiText>
+    </Fragment>
+  ) : (
+    <EuiTitle size="s">
+      <h3 id="flyoutTitle">
+        <FormattedMessage
+          defaultMessage="Edit connector"
+          id="xpack.triggersActionsUI.sections.editConnectorForm.flyoutPreconfiguredTitle"
+        />
+        &emsp;
+        <EuiBetaBadge
+          label="Beta"
+          tooltipContent={i18n.translate(
+            'xpack.triggersActionsUI.sections.editConnectorForm.betaBadgeTooltipContent',
+            {
+              defaultMessage:
+                '{pluginName} is in beta and is subject to change. The design and code is less mature than official GA features and is being provided as-is with no warranties. Beta features are not subject to the support SLA of official GA features.',
+              values: {
+                pluginName: PLUGIN.getI18nName(i18n),
+              },
+            }
+          )}
+        />
+      </h3>
+    </EuiTitle>
+  );
+
   return (
-    <EuiFlyout onClose={closeFlyout} aria-labelledby="flyoutActionAddTitle" size="m">
+    <EuiFlyout onClose={closeFlyout} aria-labelledby="flyoutActionEditTitle" size="m">
       <EuiFlyoutHeader hasBorder>
         <EuiFlexGroup gutterSize="s" alignItems="center">
           {actionTypeModel ? (
@@ -100,41 +171,37 @@ export const ConnectorEditFlyout = ({
               <EuiIcon type={actionTypeModel.iconClass} size="m" />
             </EuiFlexItem>
           ) : null}
-          <EuiFlexItem>
-            <EuiTitle size="s">
-              <h3 id="flyoutTitle">
-                <FormattedMessage
-                  defaultMessage="Edit connector"
-                  id="xpack.triggersActionsUI.sections.editConnectorForm.flyoutTitle"
-                />
-                &emsp;
-                <EuiBetaBadge
-                  label="Beta"
-                  tooltipContent={i18n.translate(
-                    'xpack.triggersActionsUI.sections.editConnectorForm.betaBadgeTooltipContent',
-                    {
-                      defaultMessage:
-                        '{pluginName} is in beta and is subject to change. The design and code is less mature than official GA features and is being provided as-is with no warranties. Beta features are not subject to the support SLA of official GA features.',
-                      values: {
-                        pluginName: PLUGIN.getI18nName(i18n),
-                      },
-                    }
-                  )}
-                />
-              </h3>
-            </EuiTitle>
-          </EuiFlexItem>
+          <EuiFlexItem>{flyoutTitle}</EuiFlexItem>
         </EuiFlexGroup>
       </EuiFlyoutHeader>
       <EuiFlyoutBody>
-        <ActionConnectorForm
-          connector={connector}
-          errors={errors}
-          actionTypeName={connector.actionType}
-          dispatch={dispatch}
-          actionTypeRegistry={actionTypeRegistry}
-          http={http}
-        />
+        {!connector.isPreconfigured ? (
+          <ActionConnectorForm
+            connector={connector}
+            errors={errors}
+            actionTypeName={connector.actionType}
+            dispatch={dispatch}
+            actionTypeRegistry={actionTypeRegistry}
+            http={http}
+          />
+        ) : (
+          <Fragment>
+            <EuiText>
+              {i18n.translate(
+                'xpack.triggersActionsUI.sections.editConnectorForm.descriptionText',
+                {
+                  defaultMessage: 'This connector is readonly.',
+                }
+              )}
+            </EuiText>
+            <EuiLink href="https://www.elastic.co/guide" target="_blank">
+              <FormattedMessage
+                id="xpack.triggersActionsUI.sections.editConnectorForm.preconfiguredHelpLabel"
+                defaultMessage="Learn more about pre-configured connectors."
+              />
+            </EuiLink>
+          </Fragment>
+        )}
       </EuiFlyoutBody>
       <EuiFlyoutFooter>
         <EuiFlexGroup justifyContent="spaceBetween">
@@ -148,7 +215,7 @@ export const ConnectorEditFlyout = ({
               )}
             </EuiButtonEmpty>
           </EuiFlexItem>
-          {canSave && actionTypeModel ? (
+          {canSave && actionTypeModel && !connector.isPreconfigured ? (
             <EuiFlexItem grow={false}>
               <EuiButton
                 fill
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx
index 4fa1e7e4c6e4d..01d21e954bbf3 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx
@@ -111,6 +111,7 @@ describe('actions_connectors_list component with items', () => {
         id: '1',
         actionTypeId: 'test',
         description: 'My test',
+        isPreconfigured: false,
         referencedByCount: 1,
         config: {},
       },
@@ -119,6 +120,15 @@ describe('actions_connectors_list component with items', () => {
         actionTypeId: 'test2',
         description: 'My test 2',
         referencedByCount: 1,
+        isPreconfigured: false,
+        config: {},
+      },
+      {
+        id: '3',
+        actionTypeId: 'test2',
+        description: 'My preconfigured test 2',
+        referencedByCount: 1,
+        isPreconfigured: true,
         config: {},
       },
     ]);
@@ -185,7 +195,11 @@ describe('actions_connectors_list component with items', () => {
 
   it('renders table of connectors', () => {
     expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1);
-    expect(wrapper.find('EuiTableRow')).toHaveLength(2);
+    expect(wrapper.find('EuiTableRow')).toHaveLength(3);
+  });
+
+  it('renders table with preconfigured connectors', () => {
+    expect(wrapper.find('[data-test-subj="preConfiguredTitleMessage"]')).toHaveLength(2);
   });
 
   test('if select item for edit should render ConnectorEditFlyout', () => {
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx
index 47e058f473946..043a644489d82 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx
@@ -15,6 +15,9 @@ import {
   EuiIconTip,
   EuiFlexGroup,
   EuiFlexItem,
+  EuiBetaBadge,
+  EuiToolTip,
+  EuiButtonIcon,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
@@ -200,31 +203,58 @@ export const ActionsConnectorsList: React.FunctionComponent = () => {
       },
     },
     {
-      field: '',
+      field: 'isPreconfigured',
       name: '',
-      actions: [
-        {
-          enabled: () => canDelete,
-          'data-test-subj': 'deleteConnector',
-          name: i18n.translate(
-            'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionName',
-            { defaultMessage: 'Delete' }
-          ),
-          description: canDelete
-            ? i18n.translate(
-                'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDescription',
-                { defaultMessage: 'Delete this connector' }
-              )
-            : i18n.translate(
-                'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDisabledDescription',
-                { defaultMessage: 'Unable to delete connectors' }
-              ),
-          type: 'icon',
-          icon: 'trash',
-          color: 'danger',
-          onClick: (item: ActionConnectorTableItem) => setConnectorsToDelete([item.id]),
-        },
-      ],
+      render: (value: number, item: ActionConnectorTableItem) => {
+        if (item.isPreconfigured) {
+          return (
+            <EuiFlexGroup justifyContent="flexEnd" alignItems="flexEnd">
+              <EuiFlexItem grow={false}>
+                <EuiBetaBadge
+                  data-test-subj="preConfiguredTitleMessage"
+                  label={i18n.translate(
+                    'xpack.triggersActionsUI.sections.alertForm.preconfiguredTitleMessage',
+                    {
+                      defaultMessage: 'Pre-configured',
+                    }
+                  )}
+                  tooltipContent="This connector can't be deleted."
+                />
+              </EuiFlexItem>
+            </EuiFlexGroup>
+          );
+        }
+        return (
+          <EuiFlexGroup justifyContent="flexEnd" alignItems="flexEnd">
+            <EuiFlexItem grow={false}>
+              <EuiToolTip
+                content={
+                  canDelete
+                    ? i18n.translate(
+                        'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDescription',
+                        { defaultMessage: 'Delete this connector' }
+                      )
+                    : i18n.translate(
+                        'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDisabledDescription',
+                        { defaultMessage: 'Unable to delete connectors' }
+                      )
+                }
+              >
+                <EuiButtonIcon
+                  isDisabled={!canDelete}
+                  data-test-subj="deleteConnector"
+                  aria-label={i18n.translate(
+                    'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionName',
+                    { defaultMessage: 'Delete' }
+                  )}
+                  onClick={() => setConnectorsToDelete([item.id])}
+                  iconType={'trash'}
+                />
+              </EuiToolTip>
+            </EuiFlexItem>
+          </EuiFlexGroup>
+        );
+      },
     },
   ];
 
diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts
index 029af1ea06e4f..c94e7116c5cea 100644
--- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts
+++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts
@@ -65,23 +65,21 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
       // need this two out of popup clicks to close them
       await nameInput.click();
 
+      // test for normal connector
+      await testSubjects.click('.webhook-ActionTypeSelectOption');
+      const webhookBodyInput = await find.byCssSelector('.ace_text-input');
+      await webhookBodyInput.focus();
+      await webhookBodyInput.type('{\\"test\\":1}');
+
+      await testSubjects.click('addAlertActionButton');
+      // pre-configured connector is loaded an displayed correctly
       await testSubjects.click('.slack-ActionTypeSelectOption');
-      await testSubjects.click('createActionConnectorButton');
-      const connectorNameInput = await testSubjects.find('nameInput');
-      await connectorNameInput.click();
-      await connectorNameInput.clearValue();
-      const connectorName = generateUniqueKey();
-      await connectorNameInput.type(connectorName);
-      const slackWebhookUrlInput = await testSubjects.find('slackWebhookUrlInput');
-      await slackWebhookUrlInput.click();
-      await slackWebhookUrlInput.clearValue();
-      await slackWebhookUrlInput.type('https://test');
-      await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)');
+      expect(await (await find.byCssSelector('#my-slack1')).isDisplayed()).to.be(true);
       const loggingMessageInput = await testSubjects.find('slackMessageTextArea');
       await loggingMessageInput.click();
       await loggingMessageInput.clearValue();
       await loggingMessageInput.type('test message');
-      await testSubjects.click('slackAddVariableButton');
+      await testSubjects.click('messageAddVariableButton');
       const variableMenuButton = await testSubjects.find('variableMenuButton-0');
       await variableMenuButton.click();
       await testSubjects.click('saveAlertButton');
diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts
index b5bcd33c3b9ab..0e6f991be24d0 100644
--- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts
+++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts
@@ -184,5 +184,30 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
       const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getConnectorsList();
       expect(searchResultsAfterDelete.length).to.eql(0);
     });
+
+    it('should not be able to delete a pre-configured connector', async () => {
+      const preconfiguredConnectorName = 'xyz';
+      await pageObjects.triggersActionsUI.searchConnectors(preconfiguredConnectorName);
+
+      const searchResults = await pageObjects.triggersActionsUI.getConnectorsList();
+      expect(searchResults.length).to.eql(1);
+
+      expect(await testSubjects.exists('deleteConnector')).to.be(false);
+      expect(await testSubjects.exists('preConfiguredTitleMessage')).to.be(true);
+    });
+
+    it('should not be able to edit a pre-configured connector', async () => {
+      const preconfiguredConnectorName = 'xyz';
+
+      await pageObjects.triggersActionsUI.searchConnectors(preconfiguredConnectorName);
+
+      const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList();
+      expect(searchResultsBeforeEdit.length).to.eql(1);
+
+      await find.clickByCssSelector('[data-test-subj="connectorsTableCell-name"] button');
+
+      expect(await testSubjects.exists('preconfiguredBadge')).to.be(true);
+      expect(await testSubjects.exists('saveEditedActionButton')).to.be(false);
+    });
   });
 };
diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts
index 538817bd9d14c..a620b1d953376 100644
--- a/x-pack/test/functional_with_es_ssl/config.ts
+++ b/x-pack/test/functional_with_es_ssl/config.ts
@@ -52,6 +52,16 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) {
         `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`,
         '--xpack.actions.enabled=true',
         '--xpack.alerting.enabled=true',
+        `--xpack.actions.preconfigured=${JSON.stringify([
+          {
+            id: 'my-slack1',
+            actionTypeId: '.slack',
+            name: 'Slack#xyz',
+            config: {
+              webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz',
+            },
+          },
+        ])}`,
       ],
     },
   };

From cc85573c8adec5ad5f3828688136c190b8d79e8b Mon Sep 17 00:00:00 2001
From: Brandon Kobel <brandon.kobel@elastic.co>
Date: Fri, 10 Apr 2020 16:01:30 -0700
Subject: [PATCH 65/78] TaskManager tasks scheduled without attempting to run
 (#62078)

* TaskManager tasks scheduled without attempting to run

* Removing unused import

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 x-pack/plugins/task_manager/server/task_manager.ts | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/x-pack/plugins/task_manager/server/task_manager.ts b/x-pack/plugins/task_manager/server/task_manager.ts
index c3f24a4aae88a..a7c67d190e72e 100644
--- a/x-pack/plugins/task_manager/server/task_manager.ts
+++ b/x-pack/plugins/task_manager/server/task_manager.ts
@@ -9,7 +9,7 @@ import { filter } from 'rxjs/operators';
 import { performance } from 'perf_hooks';
 
 import { pipe } from 'fp-ts/lib/pipeable';
-import { Option, none, some, map as mapOptional } from 'fp-ts/lib/Option';
+import { Option, some, map as mapOptional } from 'fp-ts/lib/Option';
 import {
   SavedObjectsSerializer,
   IScopedClusterClient,
@@ -156,8 +156,8 @@ export class TaskManager {
     this.events$.next(event);
   };
 
-  private attemptToRun(task: Option<string> = none) {
-    this.claimRequests$.next(task);
+  private attemptToRun(task: string) {
+    this.claimRequests$.next(some(task));
   }
 
   private createTaskRunnerForTask = (instance: ConcreteTaskInstance) => {
@@ -280,9 +280,7 @@ export class TaskManager {
       ...options,
       taskInstance: ensureDeprecatedFieldsAreCorrected(taskInstance, this.logger),
     });
-    const result = await this.store.schedule(modifiedTask);
-    this.attemptToRun();
-    return result;
+    return await this.store.schedule(modifiedTask);
   }
 
   /**
@@ -298,7 +296,7 @@ export class TaskManager {
         .then(resolve)
         .catch(reject);
 
-      this.attemptToRun(some(taskId));
+      this.attemptToRun(taskId);
     });
   }
 

From 53ee20b306556b9cecc7f94533481c43eed25b35 Mon Sep 17 00:00:00 2001
From: Yuliia Naumenko <jo.naumenko@gmail.com>
Date: Fri, 10 Apr 2020 19:18:19 -0700
Subject: [PATCH 66/78] Changed alerting wrong param name for help
 xpack.encrypted_saved_objects.encryptionKey to
 xpack.encryptedSavedObjects.encryptionKey (#63307)

---
 docs/settings/alert-action-settings.asciidoc                  | 4 ++--
 docs/user/alerting/index.asciidoc                             | 2 +-
 rfcs/text/0002_encrypted_attributes.md                        | 2 +-
 .../public/application/components/health_check.test.tsx       | 2 +-
 .../public/application/components/health_check.tsx            | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc
index d7f1ec637d1df..d4dbe9407b7a9 100644
--- a/docs/settings/alert-action-settings.asciidoc
+++ b/docs/settings/alert-action-settings.asciidoc
@@ -9,7 +9,7 @@ Alerts and actions are enabled by default in {kib}, but require you configure th
 
 . <<using-kibana-with-security,Set up {kib} to work with {stack} {security-features}>>.
 . <<configuring-tls-kib-es,Set up TLS encryption between {kib} and {es}>>.
-. <<general-alert-action-settings,Specify a value for `xpack.encrypted_saved_objects.encryptionKey`>>.
+. <<general-alert-action-settings,Specify a value for `xpack.encryptedSavedObjects.encryptionKey`>>.
 
 You can configure the following settings in the `kibana.yml` file.
 
@@ -18,7 +18,7 @@ You can configure the following settings in the `kibana.yml` file.
 [[general-alert-action-settings]]
 ==== General settings
 
-`xpack.encrypted_saved_objects.encryptionKey`::
+`xpack.encryptedSavedObjects.encryptionKey`::
 
 A string of 32 or more characters used to encrypt sensitive properties on alerts and actions before they're stored in {es}. Third party credentials &mdash; such as the username and password used to connect to an SMTP service &mdash; are an example of encrypted properties.  
 +
diff --git a/docs/user/alerting/index.asciidoc b/docs/user/alerting/index.asciidoc
index c7cf1186a44be..f556cf71bf06c 100644
--- a/docs/user/alerting/index.asciidoc
+++ b/docs/user/alerting/index.asciidoc
@@ -157,7 +157,7 @@ Pre-packaged *alert types* simplify setup, hide the details complex domain-speci
 If you are using an *on-premises* Elastic Stack deployment with <<using-kibana-with-security, *security*>>:
 
 * TLS must be configured for communication <<configuring-tls-kib-es, between {es} and {kib}>>. {kib} alerting uses <<api-keys, API keys>> to secure background alert checks and actions, and API keys require {ref}/configuring-tls.html#tls-http[TLS on the HTTP interface].
-* In the kibana.yml configuration file, add the <<alert-action-settings-kb,`xpack.encrypted_saved_objects.encryptionKey` setting>> 
+* In the kibana.yml configuration file, add the <<alert-action-settings-kb,`xpack.encryptedSavedObjects.encryptionKey` setting>> 
 
 [float]
 [[alerting-security]]
diff --git a/rfcs/text/0002_encrypted_attributes.md b/rfcs/text/0002_encrypted_attributes.md
index aa7307edb66bd..c6553c177d995 100644
--- a/rfcs/text/0002_encrypted_attributes.md
+++ b/rfcs/text/0002_encrypted_attributes.md
@@ -166,7 +166,7 @@ take a look at the source code of this library to know how encryption is perform
 parameters are used, but in short it's AES Encryption with AES-256-GCM that uses random initialization vector and salt.
 
 As with encryption key for Kibana's session cookie, master encryption key used by `encrypted_saved_objects` plugin can be
-defined as a configuration value (`xpack.encrypted_saved_objects.encryptionKey`) via `kibana.yml`, but it's **highly 
+defined as a configuration value (`xpack.encryptedSavedObjects.encryptionKey`) via `kibana.yml`, but it's **highly 
 recommended** to define this key in the [Kibana Keystore](https://www.elastic.co/guide/en/kibana/current/secure-settings.html)
 instead. The master key should be cryptographically safe and be equal or greater than 32 bytes.
 
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
index 9c51139993b3f..3fbcd13e98f5d 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx
@@ -92,7 +92,7 @@ describe('health check', () => {
 
     const description = queryByRole(/banner/i);
     expect(description!.textContent).toMatchInlineSnapshot(
-      `"To create an alert, set a value for xpack.encrypted_saved_objects.encryptionKey in your kibana.yml file. Learn how."`
+      `"To create an alert, set a value for xpack.encryptedSavedObjects.encryptionKey in your kibana.yml file. Learn how."`
     );
 
     const action = queryByText(/Learn/i);
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx
index c967cf5de0771..afd5e08f52f25 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx
@@ -132,7 +132,7 @@ const EncryptionError = ({
               defaultMessage: 'To create an alert, set a value for ',
             }
           )}
-          <EuiCode>{'xpack.encrypted_saved_objects.encryptionKey'}</EuiCode>
+          <EuiCode>{'xpack.encryptedSavedObjects.encryptionKey'}</EuiCode>
           {i18n.translate(
             'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey',
             {

From bd159c7d59979d66c09c94402daf2c30373ee9f9 Mon Sep 17 00:00:00 2001
From: Pierre Gayvallet <pierre.gayvallet@elastic.co>
Date: Sat, 11 Apr 2020 09:27:45 +0200
Subject: [PATCH 67/78] fix ScopedHistory.createHref to prepend location with
 scoped history basePath (#62407)

* fix createHref to prepend with scoped history basePath + add option to exclude it.

* fix prependBasePath behavior

* fix test plugins urls

* add pathname to endpoint url builder methods

* Revert "add pathname to endpoint url builder methods"

This reverts commit 7604932b

* adapt createHref instead of prependBasePath

* use object options for createHref

* update generated doc
---
 ...in-core-public.scopedhistory.createhref.md |  6 +++--
 ...kibana-plugin-core-public.scopedhistory.md |  2 +-
 .../public/application/scoped_history.test.ts | 25 +++++++++++++++++--
 src/core/public/application/scoped_history.ts | 20 ++++++++++++---
 src/core/public/public.api.md                 |  4 ++-
 .../core_plugin_a/public/application.tsx      |  2 +-
 .../core_plugin_b/public/application.tsx      |  2 +-
 7 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/docs/development/core/public/kibana-plugin-core-public.scopedhistory.createhref.md b/docs/development/core/public/kibana-plugin-core-public.scopedhistory.createhref.md
index 7058656d09947..6bbab43ff6ffc 100644
--- a/docs/development/core/public/kibana-plugin-core-public.scopedhistory.createhref.md
+++ b/docs/development/core/public/kibana-plugin-core-public.scopedhistory.createhref.md
@@ -4,10 +4,12 @@
 
 ## ScopedHistory.createHref property
 
-Creates an href (string) to the location.
+Creates an href (string) to the location. If `prependBasePath` is true (default), it will prepend the location's path with the scoped history basePath.
 
 <b>Signature:</b>
 
 ```typescript
-createHref: (location: LocationDescriptorObject<HistoryLocationState>) => string;
+createHref: (location: LocationDescriptorObject<HistoryLocationState>, { prependBasePath }?: {
+        prependBasePath?: boolean | undefined;
+    }) => string;
 ```
diff --git a/docs/development/core/public/kibana-plugin-core-public.scopedhistory.md b/docs/development/core/public/kibana-plugin-core-public.scopedhistory.md
index 5ea47d2090d71..fa29b32c0bafc 100644
--- a/docs/development/core/public/kibana-plugin-core-public.scopedhistory.md
+++ b/docs/development/core/public/kibana-plugin-core-public.scopedhistory.md
@@ -28,7 +28,7 @@ export declare class ScopedHistory<HistoryLocationState = unknown> implements Hi
 |  --- | --- | --- | --- |
 |  [action](./kibana-plugin-core-public.scopedhistory.action.md) |  | <code>Action</code> | The last action dispatched on the history stack. |
 |  [block](./kibana-plugin-core-public.scopedhistory.block.md) |  | <code>(prompt?: string &#124; boolean &#124; History.TransitionPromptHook&lt;HistoryLocationState&gt; &#124; undefined) =&gt; UnregisterCallback</code> | Not supported. Use [AppMountParameters.onAppLeave](./kibana-plugin-core-public.appmountparameters.onappleave.md)<!-- -->. |
-|  [createHref](./kibana-plugin-core-public.scopedhistory.createhref.md) |  | <code>(location: LocationDescriptorObject&lt;HistoryLocationState&gt;) =&gt; string</code> | Creates an href (string) to the location. |
+|  [createHref](./kibana-plugin-core-public.scopedhistory.createhref.md) |  | <code>(location: LocationDescriptorObject&lt;HistoryLocationState&gt;, { prependBasePath }?: {</code><br/><code>        prependBasePath?: boolean &#124; undefined;</code><br/><code>    }) =&gt; string</code> | Creates an href (string) to the location. If <code>prependBasePath</code> is true (default), it will prepend the location's path with the scoped history basePath. |
 |  [createSubHistory](./kibana-plugin-core-public.scopedhistory.createsubhistory.md) |  | <code>&lt;SubHistoryLocationState = unknown&gt;(basePath: string) =&gt; ScopedHistory&lt;SubHistoryLocationState&gt;</code> | Creates a <code>ScopedHistory</code> for a subpath of this <code>ScopedHistory</code>. Useful for applications that may have sub-apps that do not need access to the containing application's history. |
 |  [go](./kibana-plugin-core-public.scopedhistory.go.md) |  | <code>(n: number) =&gt; void</code> | Send the user forward or backwards in the history stack. |
 |  [goBack](./kibana-plugin-core-public.scopedhistory.goback.md) |  | <code>() =&gt; void</code> | Send the user one location back in the history stack. Equivalent to calling [ScopedHistory.go(-1)](./kibana-plugin-core-public.scopedhistory.go.md)<!-- -->. If no more entries are available backwards, this is a no-op. |
diff --git a/src/core/public/application/scoped_history.test.ts b/src/core/public/application/scoped_history.test.ts
index c01eb50830516..a56cffef1e2f2 100644
--- a/src/core/public/application/scoped_history.test.ts
+++ b/src/core/public/application/scoped_history.test.ts
@@ -268,11 +268,32 @@ describe('ScopedHistory', () => {
       const gh = createMemoryHistory();
       gh.push('/app/wow');
       const h = new ScopedHistory(gh, '/app/wow');
-      expect(h.createHref({ pathname: '' })).toEqual(`/`);
+      expect(h.createHref({ pathname: '' })).toEqual(`/app/wow`);
+      expect(h.createHref({})).toEqual(`/app/wow`);
       expect(h.createHref({ pathname: '/new-page', search: '?alpha=true' })).toEqual(
-        `/new-page?alpha=true`
+        `/app/wow/new-page?alpha=true`
       );
     });
+
+    it('behave correctly with slash-ending basePath', () => {
+      const gh = createMemoryHistory();
+      gh.push('/app/wow/');
+      const h = new ScopedHistory(gh, '/app/wow/');
+      expect(h.createHref({ pathname: '' })).toEqual(`/app/wow/`);
+      expect(h.createHref({ pathname: '/new-page', search: '?alpha=true' })).toEqual(
+        `/app/wow/new-page?alpha=true`
+      );
+    });
+
+    it('skips the scoped history path when `prependBasePath` is false', () => {
+      const gh = createMemoryHistory();
+      gh.push('/app/wow');
+      const h = new ScopedHistory(gh, '/app/wow');
+      expect(h.createHref({ pathname: '' }, { prependBasePath: false })).toEqual(`/`);
+      expect(
+        h.createHref({ pathname: '/new-page', search: '?alpha=true' }, { prependBasePath: false })
+      ).toEqual(`/new-page?alpha=true`);
+    });
   });
 
   describe('action', () => {
diff --git a/src/core/public/application/scoped_history.ts b/src/core/public/application/scoped_history.ts
index c5febc7604feb..9fa8f0b7f8148 100644
--- a/src/core/public/application/scoped_history.ts
+++ b/src/core/public/application/scoped_history.ts
@@ -219,11 +219,26 @@ export class ScopedHistory<HistoryLocationState = unknown>
 
   /**
    * Creates an href (string) to the location.
+   * If `prependBasePath` is true (default), it will prepend the location's path with the scoped history basePath.
    *
    * @param location
+   * @param prependBasePath
    */
-  public createHref = (location: LocationDescriptorObject<HistoryLocationState>): Href => {
+  public createHref = (
+    location: LocationDescriptorObject<HistoryLocationState>,
+    { prependBasePath = true }: { prependBasePath?: boolean } = {}
+  ): Href => {
     this.verifyActive();
+    if (prependBasePath) {
+      location = this.prependBasePath(location);
+      if (location.pathname === undefined) {
+        // we always want to create an url relative to the basePath
+        // so if pathname is not present, we use the history's basePath as default
+        // we are doing that here because `prependBasePath` should not
+        // alter pathname for other method calls
+        location.pathname = this.basePath;
+      }
+    }
     return this.parentHistory.createHref(location);
   };
 
@@ -254,8 +269,7 @@ export class ScopedHistory<HistoryLocationState = unknown>
    * Prepends the base path to string.
    */
   private prependBasePathToString(path: string): string {
-    path = path.startsWith('/') ? path.slice(1) : path;
-    return path.length ? `${this.basePath}/${path}` : this.basePath;
+    return path.length ? `${this.basePath}/${path}`.replace(/\/{2,}/g, '/') : this.basePath;
   }
 
   /**
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index a5aa37becabc2..6d95d1bc7069c 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -1196,7 +1196,9 @@ export class ScopedHistory<HistoryLocationState = unknown> implements History<Hi
     constructor(parentHistory: History, basePath: string);
     get action(): Action;
     block: (prompt?: string | boolean | History.TransitionPromptHook<HistoryLocationState> | undefined) => UnregisterCallback;
-    createHref: (location: LocationDescriptorObject<HistoryLocationState>) => string;
+    createHref: (location: LocationDescriptorObject<HistoryLocationState>, { prependBasePath }?: {
+        prependBasePath?: boolean | undefined;
+    }) => string;
     createSubHistory: <SubHistoryLocationState = unknown>(basePath: string) => ScopedHistory<SubHistoryLocationState>;
     go: (n: number) => void;
     goBack: () => void;
diff --git a/test/plugin_functional/plugins/core_plugin_a/public/application.tsx b/test/plugin_functional/plugins/core_plugin_a/public/application.tsx
index abea970749cbc..159bb54f50903 100644
--- a/test/plugin_functional/plugins/core_plugin_a/public/application.tsx
+++ b/test/plugin_functional/plugins/core_plugin_a/public/application.tsx
@@ -95,7 +95,7 @@ const Nav = withRouter(({ history, navigateToApp }: NavProps) => (
           {
             id: 'home',
             name: 'Home',
-            onClick: () => history.push('/'),
+            onClick: () => history.push(''),
             'data-test-subj': 'fooNavHome',
           },
           {
diff --git a/test/plugin_functional/plugins/core_plugin_b/public/application.tsx b/test/plugin_functional/plugins/core_plugin_b/public/application.tsx
index 447307920c04c..01a63f9782563 100644
--- a/test/plugin_functional/plugins/core_plugin_b/public/application.tsx
+++ b/test/plugin_functional/plugins/core_plugin_b/public/application.tsx
@@ -102,7 +102,7 @@ const Nav = withRouter(({ history, navigateToApp }: NavProps) => (
           {
             id: 'home',
             name: 'Home',
-            onClick: () => navigateToApp('bar', { path: '/' }),
+            onClick: () => navigateToApp('bar', { path: '' }),
             'data-test-subj': 'barNavHome',
           },
           {

From 2be6b7fdcecbe2848cc1da23eb98af756f513d6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cau=C3=AA=20Marcondes?=
 <55978943+cauemarcondes@users.noreply.github.com>
Date: Sat, 11 Apr 2020 10:06:39 +0100
Subject: [PATCH 68/78] fixing custom link popover size and hiding scroll
 (#63240)

---
 .../TransactionActionMenu/CustomLink/CustomLinkPopover.tsx      | 1 +
 .../shared/TransactionActionMenu/TransactionActionMenu.tsx      | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx
index a20bc7e21cfc5..3aed1b7ac2953 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx
@@ -19,6 +19,7 @@ import { ManageCustomLink } from './ManageCustomLink';
 import { px } from '../../../../style/variables';
 
 const ScrollableContainer = styled.div`
+  -ms-overflow-style: none;
   max-height: ${px(535)};
   overflow: scroll;
 `;
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
index e3fbcf8485d54..7ebfe26b83630 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
@@ -124,7 +124,7 @@ export const TransactionActionMenu: FunctionComponent<Props> = ({
           <ActionMenuButton onClick={() => setIsActionPopoverOpen(true)} />
         }
       >
-        <div style={{ maxHeight: px(600) }}>
+        <div style={{ maxHeight: px(600), width: px(335) }}>
           {isCustomLinksPopoverOpen ? (
             <CustomLinkPopover
               customLinks={customLinks.slice(3, customLinks.length)}

From 1199c8c8b0c988d9013149b586bb9a5c941f1072 Mon Sep 17 00:00:00 2001
From: Anton Dosov <anton.dosov@elastic.co>
Date: Sun, 12 Apr 2020 17:06:03 +0200
Subject: [PATCH 69/78] Bugfix dashboard unpins filters (#62301)

Fixes following cases:

Saving dashboard with pinned filter unpins it. Do not save pinned filters with dashboard see #62301 (comment)
When navigating with global filter to dashboard with same saved filter, filter becomes unpinned
When navigating from listing to dashboard with saved filter, back button didn't work

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../application/dashboard_app_controller.tsx  | 14 +++++--
 .../application/dashboard_state_manager.ts    |  7 ++--
 .../public/application/lib/filter_utils.ts    |  2 +-
 .../application/lib/update_saved_dashboard.ts |  7 ++++
 .../filter_manager/filter_manager.test.ts     | 11 +++---
 .../query/filter_manager/filter_manager.ts    | 17 ++-------
 .../data/public/ui/filter_bar/filter_item.tsx |  3 +-
 .../apps/dashboard/dashboard_filter_bar.js    | 38 +++++++++++++++++++
 test/functional/services/filter_bar.ts        | 15 +++++++-
 9 files changed, 85 insertions(+), 29 deletions(-)

diff --git a/src/plugins/dashboard/public/application/dashboard_app_controller.tsx b/src/plugins/dashboard/public/application/dashboard_app_controller.tsx
index d1c7d2d9eba3e..babd1fac274eb 100644
--- a/src/plugins/dashboard/public/application/dashboard_app_controller.tsx
+++ b/src/plugins/dashboard/public/application/dashboard_app_controller.tsx
@@ -143,6 +143,7 @@ export class DashboardAppController {
     });
 
     // sync initial app filters from state to filterManager
+    // if there is an existing similar global filter, then leave it as global
     filterManager.setAppFilters(_.cloneDeep(dashboardStateManager.appState.filters));
     // setup syncing of app filters between appState and filterManager
     const stopSyncingAppFilters = connectToQueryState(
@@ -150,7 +151,11 @@ export class DashboardAppController {
       {
         set: ({ filters }) => dashboardStateManager.setFilters(filters || []),
         get: () => ({ filters: dashboardStateManager.appState.filters }),
-        state$: dashboardStateManager.appState$.pipe(map(state => ({ filters: state.filters }))),
+        state$: dashboardStateManager.appState$.pipe(
+          map(state => ({
+            filters: state.filters,
+          }))
+        ),
       },
       {
         filters: esFilters.FilterStateStore.APP_STATE,
@@ -170,13 +175,16 @@ export class DashboardAppController {
     }
 
     // starts syncing `_g` portion of url with query services
-    // note: dashboard_state_manager.ts syncs `_a` portion of url
     // it is important to start this syncing after `dashboardStateManager.syncTimefilterWithDashboard(timefilter);` above is run,
-    // otherwise it will case redundant browser history record
+    // otherwise it will case redundant browser history records
     const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl(
       queryService,
       kbnUrlStateStorage
     );
+
+    // starts syncing `_a` portion of url
+    dashboardStateManager.startStateSyncing();
+
     $scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean;
 
     const getShouldShowEditHelp = () =>
diff --git a/src/plugins/dashboard/public/application/dashboard_state_manager.ts b/src/plugins/dashboard/public/application/dashboard_state_manager.ts
index 6025f535ae761..13ba3c6d0b60d 100644
--- a/src/plugins/dashboard/public/application/dashboard_state_manager.ts
+++ b/src/plugins/dashboard/public/application/dashboard_state_manager.ts
@@ -164,9 +164,6 @@ export class DashboardStateManager {
       this.changeListeners.forEach(listener => listener({ dirty: this.isDirty }));
     });
 
-    // make sure url ('_a') matches initial state
-    this.kbnUrlStateStorage.set(this.STATE_STORAGE_KEY, initialState, { replace: true });
-
     // setup state syncing utils. state container will be synced with url into `this.STATE_STORAGE_KEY` query param
     this.stateSyncRef = syncState<DashboardAppState>({
       storageKey: this.STATE_STORAGE_KEY,
@@ -201,8 +198,10 @@ export class DashboardStateManager {
       },
       stateStorage: this.kbnUrlStateStorage,
     });
+  }
 
-    // actually start syncing state with container
+  public startStateSyncing() {
+    this.saveState({ replace: true });
     this.stateSyncRef.start();
   }
 
diff --git a/src/plugins/dashboard/public/application/lib/filter_utils.ts b/src/plugins/dashboard/public/application/lib/filter_utils.ts
index 1ec231db0c3d2..775bf90643a21 100644
--- a/src/plugins/dashboard/public/application/lib/filter_utils.ts
+++ b/src/plugins/dashboard/public/application/lib/filter_utils.ts
@@ -19,7 +19,7 @@
 
 import _ from 'lodash';
 import moment, { Moment } from 'moment';
-import { Filter } from 'src/plugins/data/public';
+import { Filter } from '../../../../data/public';
 
 /**
  * @typedef {Object} QueryFilter
diff --git a/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts b/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts
index 53dc7d9b460de..fc519327b41ee 100644
--- a/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts
+++ b/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts
@@ -22,6 +22,7 @@ import { RefreshInterval, TimefilterContract } from 'src/plugins/data/public';
 import { FilterUtils } from './filter_utils';
 import { SavedObjectDashboard } from '../../saved_dashboards';
 import { DashboardAppState } from '../../types';
+import { esFilters } from '../../../../data/public';
 
 export function updateSavedDashboard(
   savedDashboard: SavedObjectDashboard,
@@ -48,4 +49,10 @@ export function updateSavedDashboard(
     'value',
   ]);
   savedDashboard.refreshInterval = savedDashboard.timeRestore ? timeRestoreObj : undefined;
+
+  // save only unpinned filters
+  const unpinnedFilters = savedDashboard
+    .getFilters()
+    .filter(filter => !esFilters.isFilterPinned(filter));
+  savedDashboard.searchSource.setField('filter', unpinnedFilters);
 }
diff --git a/src/plugins/data/public/query/filter_manager/filter_manager.test.ts b/src/plugins/data/public/query/filter_manager/filter_manager.test.ts
index ce574ace45705..3b4ca08cbbf14 100644
--- a/src/plugins/data/public/query/filter_manager/filter_manager.test.ts
+++ b/src/plugins/data/public/query/filter_manager/filter_manager.test.ts
@@ -204,18 +204,19 @@ describe('filter_manager', () => {
       ).toBe(3);
     });
 
-    test('should set app filters and remove any duplicated global filters', async function() {
-      filterManager.addFilters(readyFilters, true);
+    test('should set app filters and merge them with duplicate global filters', async function() {
+      const [filter, ...otherFilters] = readyFilters;
+      filterManager.addFilters(otherFilters, true);
       const appFilter1 = _.cloneDeep(readyFilters[1]);
       const appFilter2 = _.cloneDeep(readyFilters[2]);
 
-      filterManager.setAppFilters([appFilter1, appFilter2]);
+      filterManager.setAppFilters([filter, appFilter1, appFilter2]);
 
       const newGlobalFilters = filterManager.getGlobalFilters();
       const newAppFilters = filterManager.getAppFilters();
 
-      expect(newGlobalFilters).toHaveLength(1);
-      expect(newAppFilters).toHaveLength(2);
+      expect(newGlobalFilters).toHaveLength(2);
+      expect(newAppFilters).toHaveLength(1);
     });
 
     test('should set global filters and remove any duplicated app filters', async function() {
diff --git a/src/plugins/data/public/query/filter_manager/filter_manager.ts b/src/plugins/data/public/query/filter_manager/filter_manager.ts
index fba1866ebd615..e206286bce147 100644
--- a/src/plugins/data/public/query/filter_manager/filter_manager.ts
+++ b/src/plugins/data/public/query/filter_manager/filter_manager.ts
@@ -177,13 +177,9 @@ export class FilterManager {
   public setGlobalFilters(newGlobalFilters: Filter[]) {
     newGlobalFilters = mapAndFlattenFilters(newGlobalFilters);
     FilterManager.setFiltersStore(newGlobalFilters, FilterStateStore.GLOBAL_STATE, true);
-    const { appFilters: currentAppFilters } = this.getPartitionedFilters();
-    // remove duplicates from current app filters, to make sure global will take precedence
-    const filteredAppFilters = currentAppFilters.filter(
-      appFilter => !newGlobalFilters.find(globalFilter => compareFilters(globalFilter, appFilter))
-    );
+    const { appFilters } = this.getPartitionedFilters();
     const newFilters = this.mergeIncomingFilters({
-      appFilters: filteredAppFilters,
+      appFilters,
       globalFilters: newGlobalFilters,
     });
 
@@ -198,14 +194,9 @@ export class FilterManager {
   public setAppFilters(newAppFilters: Filter[]) {
     newAppFilters = mapAndFlattenFilters(newAppFilters);
     FilterManager.setFiltersStore(newAppFilters, FilterStateStore.APP_STATE, true);
-    const { globalFilters: currentGlobalFilters } = this.getPartitionedFilters();
-    // remove duplicates from current global filters, to make sure app will take precedence
-    const filteredGlobalFilters = currentGlobalFilters.filter(
-      globalFilter => !newAppFilters.find(appFilter => compareFilters(appFilter, globalFilter))
-    );
-
+    const { globalFilters } = this.getPartitionedFilters();
     const newFilters = this.mergeIncomingFilters({
-      globalFilters: filteredGlobalFilters,
+      globalFilters,
       appFilters: newAppFilters,
     });
     this.handleStateUpdate(newFilters);
diff --git a/src/plugins/data/public/ui/filter_bar/filter_item.tsx b/src/plugins/data/public/ui/filter_bar/filter_item.tsx
index 6b5fd41dc06ea..528ec4800e7b9 100644
--- a/src/plugins/data/public/ui/filter_bar/filter_item.tsx
+++ b/src/plugins/data/public/ui/filter_bar/filter_item.tsx
@@ -88,6 +88,7 @@ class FilterItemUI extends Component<Props, State> {
     const dataTestSubjDisabled = `filter-${
       this.props.filter.meta.disabled ? 'disabled' : 'enabled'
     }`;
+    const dataTestSubjPinned = `filter-${isFilterPinned(filter) ? 'pinned' : 'unpinned'}`;
 
     const classes = classNames(
       'globalFilterItem',
@@ -107,7 +108,7 @@ class FilterItemUI extends Component<Props, State> {
         className={classes}
         iconOnClick={() => this.props.onRemove()}
         onClick={this.handleBadgeClick}
-        data-test-subj={`filter ${dataTestSubjDisabled} ${dataTestSubjKey} ${dataTestSubjValue}`}
+        data-test-subj={`filter ${dataTestSubjDisabled} ${dataTestSubjKey} ${dataTestSubjValue} ${dataTestSubjPinned}`}
       />
     );
 
diff --git a/test/functional/apps/dashboard/dashboard_filter_bar.js b/test/functional/apps/dashboard/dashboard_filter_bar.js
index 6d2a30fa85325..f6089871010c3 100644
--- a/test/functional/apps/dashboard/dashboard_filter_bar.js
+++ b/test/functional/apps/dashboard/dashboard_filter_bar.js
@@ -27,6 +27,7 @@ export default function({ getService, getPageObjects }) {
   const pieChart = getService('pieChart');
   const esArchiver = getService('esArchiver');
   const kibanaServer = getService('kibanaServer');
+  const browser = getService('browser');
   const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'visualize', 'timePicker']);
 
   describe('dashboard filter bar', () => {
@@ -126,9 +127,46 @@ export default function({ getService, getPageObjects }) {
 
         const filterCount = await filterBar.getFilterCount();
         expect(filterCount).to.equal(1);
+        await pieChart.expectPieSliceCount(1);
+      });
 
+      it("restoring filters doesn't break back button", async () => {
+        await browser.goBack();
+        await PageObjects.dashboard.expectExistsDashboardLandingPage();
+        await browser.goForward();
+        await PageObjects.header.waitUntilLoadingHasFinished();
+        await PageObjects.dashboard.waitForRenderComplete();
         await pieChart.expectPieSliceCount(1);
       });
+
+      it("saving with pinned filter doesn't unpin them", async () => {
+        const filterKey = 'bytes';
+        await filterBar.toggleFilterPinned(filterKey);
+        await PageObjects.dashboard.switchToEditMode();
+        await PageObjects.dashboard.saveDashboard('saved with pinned filters', {
+          saveAsNew: true,
+        });
+        expect(await filterBar.isFilterPinned(filterKey)).to.be(true);
+        await pieChart.expectPieSliceCount(1);
+      });
+
+      it("navigating to a dashboard with global filter doesn't unpin it if same filter is saved with dashboard", async () => {
+        await PageObjects.dashboard.preserveCrossAppState();
+        await PageObjects.dashboard.gotoDashboardLandingPage();
+        await PageObjects.dashboard.loadSavedDashboard('with filters');
+        await PageObjects.header.waitUntilLoadingHasFinished();
+        expect(await filterBar.isFilterPinned('bytes')).to.be(true);
+        await pieChart.expectPieSliceCount(1);
+      });
+
+      it("pinned filters aren't saved", async () => {
+        await filterBar.removeFilter('bytes');
+        await PageObjects.dashboard.gotoDashboardLandingPage();
+        await PageObjects.dashboard.loadSavedDashboard('saved with pinned filters');
+        await PageObjects.header.waitUntilLoadingHasFinished();
+        expect(await filterBar.getFilterCount()).to.be(0);
+        await pieChart.expectPieSliceCount(5);
+      });
     });
 
     describe('saved search filtering', function() {
diff --git a/test/functional/services/filter_bar.ts b/test/functional/services/filter_bar.ts
index 9d494b1e6d950..a463a593e9e04 100644
--- a/test/functional/services/filter_bar.ts
+++ b/test/functional/services/filter_bar.ts
@@ -32,10 +32,16 @@ export function FilterBarProvider({ getService, getPageObjects }: FtrProviderCon
      * @param value filter value
      * @param enabled filter status
      */
-    public async hasFilter(key: string, value: string, enabled: boolean = true): Promise<boolean> {
+    public async hasFilter(
+      key: string,
+      value: string,
+      enabled: boolean = true,
+      pinned: boolean = false
+    ): Promise<boolean> {
       const filterActivationState = enabled ? 'enabled' : 'disabled';
+      const filterPinnedState = pinned ? 'pinned' : 'unpinned';
       return testSubjects.exists(
-        `filter filter-${filterActivationState} filter-key-${key} filter-value-${value}`,
+        `filter filter-${filterActivationState} filter-key-${key} filter-value-${value} filter-${filterPinnedState}`,
         {
           allowHidden: true,
         }
@@ -80,6 +86,11 @@ export function FilterBarProvider({ getService, getPageObjects }: FtrProviderCon
       await PageObjects.header.awaitGlobalLoadingIndicatorHidden();
     }
 
+    public async isFilterPinned(key: string): Promise<boolean> {
+      const filter = await testSubjects.find(`~filter & ~filter-key-${key}`);
+      return (await filter.getAttribute('data-test-subj')).includes('filter-pinned');
+    }
+
     public async getFilterCount(): Promise<number> {
       const filters = await testSubjects.findAll('~filter');
       return filters.length;

From 358d13919bc597d13e6a98ec97fae2615093027e Mon Sep 17 00:00:00 2001
From: Pierre Gayvallet <pierre.gayvallet@elastic.co>
Date: Mon, 13 Apr 2020 13:28:09 +0200
Subject: [PATCH 70/78] Migrate SO management section to NP (#61700)

* move libs to new plugin

* adapt libs to use NP apis

* add required plugins

* add get_allowed_types route

* move object_view components

* add service registry

* migrate table header component

* migrate table component

* migrate saved_objects_table component

* remove migrated legacy files

* fix re-export from legacy management + section label

* migrate services registration

* adapt management section mock

* fix imports

* migrate flyout component

* migrate relationships component

* migrate saved_objects_table tests

* migrate breadcrumb

* add redirect if unauthorized check

* migrate translations to new savedObjectsManagement prefix

* remove obsolete translations

* convert action registry to service pattern

* wire extra actions

* remove importAndExportableTypes from injected vars

* handle newIndexPatternUrl

* remove duplicate dashboard dependency

* remove old TODO

* remove old TODO

* properly mock lodash in tests

* add async management section loading

* expose createSavedSearchesLoader from discover plugin contract

* address most review comments

* fix merge conflicts
---
 src/core/public/mocks.ts                      |   6 +-
 .../server/saved_objects/service/index.ts     |   1 -
 src/core/server/server.api.md                 |   2 -
 src/legacy/core_plugins/kibana/inject_vars.js |   3 -
 .../core_plugins/kibana/public/index.ts       |   2 +-
 .../management/saved_object_registry.ts       |  64 +--
 .../public/management/sections/index.js       |   1 -
 .../management/sections/objects/_objects.html |   5 -
 .../management/sections/objects/_objects.js   | 104 -----
 .../management/sections/objects/_view.html    |   5 -
 .../management/sections/objects/_view.js      |  85 ----
 .../sections/objects/breadcrumbs.js           |  50 ---
 .../objects/components/objects_table/index.js |  20 -
 .../saved_objects/saved_objects_mixin.js      |   5 -
 src/plugins/data/public/mocks.ts              |   1 +
 src/plugins/discover/public/mocks.ts          |   3 +
 src/plugins/discover/public/plugin.ts         |  12 +
 src/plugins/management/public/mocks/index.ts  |  13 +-
 .../saved_objects_management/common/index.ts} |   2 +-
 .../saved_objects_management/common}/types.ts |  30 +-
 .../saved_objects_management/kibana.json      |   3 +-
 .../saved_objects_management/public/index.ts  |   6 +-
 .../public}/lib/case_conversion.test.ts       |   0
 .../public}/lib/case_conversion.ts            |   0
 .../public}/lib/create_field_list.test.ts     |   4 +-
 .../public}/lib/create_field_list.ts          |   8 +-
 .../lib/extract_export_details.test.ts        |   0
 .../public}/lib/extract_export_details.ts     |   0
 .../lib/fetch_export_by_type_and_search.ts    |   7 +-
 .../public}/lib/fetch_export_objects.ts       |   7 +-
 .../public}/lib/find_objects.ts               |  29 +-
 .../public/lib/get_allowed_types.ts           |  31 ++
 .../public}/lib/get_default_title.ts          |   0
 .../public}/lib/get_relationships.test.ts     |  37 +-
 .../public}/lib/get_relationships.ts          |  32 +-
 .../public}/lib/get_saved_object_counts.ts    |  17 +-
 .../public}/lib/get_saved_object_label.ts     |   0
 .../public}/lib/import_file.ts                |  14 +-
 .../public}/lib/import_legacy_file.test.ts    |   0
 .../public}/lib/import_legacy_file.ts         |   0
 .../public}/lib/in_app_url.test.ts            |   2 +-
 .../public}/lib/in_app_url.ts                 |   0
 .../public}/lib/index.ts                      |   2 +
 .../public}/lib/log_legacy_import.ts          |   9 +-
 .../public}/lib/numeric.ts                    |   0
 .../public}/lib/parse_query.test.ts           |   2 +-
 .../public}/lib/parse_query.ts                |  15 +-
 .../lib/process_import_response.test.ts       |   0
 .../public}/lib/process_import_response.ts    |   0
 .../public}/lib/resolve_import_errors.test.ts |  35 +-
 .../public}/lib/resolve_import_errors.ts      |  12 +-
 .../public}/lib/resolve_saved_objects.test.ts |   7 +-
 .../public}/lib/resolve_saved_objects.ts      |  26 +-
 .../public/management_section/index.ts}       |   2 +-
 .../management_section/mount_section.tsx      | 211 +++++++++
 .../__snapshots__/header.test.tsx.snap        |   6 +-
 .../__snapshots__/intro.test.tsx.snap         |   6 +-
 .../not_found_errors.test.tsx.snap            |  30 +-
 .../object_view/components}/field.test.tsx    |   0
 .../object_view/components}/field.tsx         |   4 +-
 .../object_view/components}/form.tsx          |  18 +-
 .../object_view/components}/header.test.tsx   |   0
 .../object_view/components}/header.tsx        |   8 +-
 .../object_view/components}/index.ts          |   0
 .../object_view/components}/intro.test.tsx    |   0
 .../object_view/components}/intro.tsx         |   4 +-
 .../components}/not_found_errors.test.tsx     |   0
 .../components}/not_found_errors.tsx          |  10 +-
 .../management_section/object_view/index.ts}  |   2 +-
 .../object_view}/saved_object_view.tsx        |  18 +-
 .../saved_objects_table.test.tsx.snap}        | 116 ++++-
 .../__snapshots__/flyout.test.tsx.snap}       |  84 ++--
 .../__snapshots__/header.test.tsx.snap}       |  10 +-
 .../relationships.test.tsx.snap}              |   2 +-
 .../__snapshots__/table.test.tsx.snap}        |  24 +-
 .../components/flyout.test.mocks.ts           |  44 ++
 .../objects_table/components/flyout.test.tsx} | 183 ++++----
 .../objects_table/components/flyout.tsx}      | 260 ++++++-----
 .../objects_table/components/header.test.tsx} |   3 +-
 .../objects_table/components/header.tsx}      |  31 +-
 .../objects_table/components/index.ts         |  23 +
 .../components/relationships.test.tsx}        |  44 +-
 .../components/relationships.tsx}             |  89 ++--
 .../objects_table/components/table.test.tsx}  |  31 +-
 .../objects_table/components/table.tsx}       | 154 ++++---
 .../objects_table/index.ts}                   |   2 +-
 .../saved_objects_table.test.mocks.ts         |  67 +++
 .../saved_objects_table.test.tsx}             | 419 ++++++++----------
 .../objects_table/saved_objects_table.tsx}    | 260 ++++++-----
 .../public/management_section/types.ts        |  38 ++
 .../saved_objects_management/public/mocks.ts  |  12 +-
 .../public/plugin.test.ts                     |  10 +-
 .../saved_objects_management/public/plugin.ts |  71 ++-
 .../public/register_services.ts               |  59 +++
 .../public/services/action_service.mock.ts    |  57 +++
 ...egistry.test.ts => action_service.test.ts} |  30 +-
 .../{action_registry.ts => action_service.ts} |  48 +-
 .../public/services/index.ts                  |  14 +-
 ...istry.mock.ts => service_registry.mock.ts} |  13 +-
 .../public/services/service_registry.ts       |  49 ++
 .../services/{action_types.ts => types.ts}    |   0
 .../saved_objects_management/public/types.ts  |  20 +
 .../server/routes/get_allowed_types.ts}       |  34 +-
 .../server/routes/index.test.ts               |   8 +-
 .../server/routes/index.ts                    |   2 +
 .../saved_objects_management/server/types.ts  |  30 +-
 ...opy_saved_objects_to_space_service.test.ts |   4 +-
 .../copy_saved_objects_to_space_service.ts    |   2 +-
 .../translations/translations/ja-JP.json      | 245 +++++-----
 .../translations/translations/zh-CN.json      | 243 +++++-----
 110 files changed, 2184 insertions(+), 1689 deletions(-)
 delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.html
 delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js
 delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/_view.html
 delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/_view.js
 delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/breadcrumbs.js
 delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/index.js
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/index.js => plugins/saved_objects_management/common/index.ts} (89%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/common}/types.ts (74%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/case_conversion.test.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/case_conversion.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/create_field_list.test.ts (96%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/create_field_list.ts (92%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/extract_export_details.test.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/extract_export_details.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/fetch_export_by_type_and_search.ts (89%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/fetch_export_objects.ts (89%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/find_objects.ts (57%)
 create mode 100644 src/plugins/saved_objects_management/public/lib/get_allowed_types.ts
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/get_default_title.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/get_relationships.test.ts (67%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/get_relationships.ts (67%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/get_saved_object_counts.ts (72%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/get_saved_object_label.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/import_file.ts (75%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/import_legacy_file.test.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/import_legacy_file.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/in_app_url.test.ts (98%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/in_app_url.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/index.ts (94%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/log_legacy_import.ts (81%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/numeric.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/parse_query.test.ts (92%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/parse_query.ts (77%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/process_import_response.test.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/process_import_response.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/resolve_import_errors.test.ts (90%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/resolve_import_errors.ts (95%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/resolve_saved_objects.test.ts (98%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public}/lib/resolve_saved_objects.ts (94%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/index.js => plugins/saved_objects_management/public/management_section/index.ts} (93%)
 create mode 100644 src/plugins/saved_objects_management/public/management_section/mount_section.tsx
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/__snapshots__/header.test.tsx.snap (96%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/__snapshots__/intro.test.tsx.snap (90%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/__snapshots__/not_found_errors.test.tsx.snap (89%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/field.test.tsx (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/field.tsx (97%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/form.tsx (89%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/header.test.tsx (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/header.tsx (92%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/index.ts (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/intro.test.tsx (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/intro.tsx (92%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/not_found_errors.test.tsx (100%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/object_view => plugins/saved_objects_management/public/management_section/object_view/components}/not_found_errors.tsx (87%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/index.js => plugins/saved_objects_management/public/management_section/object_view/index.ts} (93%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects => plugins/saved_objects_management/public/management_section/object_view}/saved_object_view.tsx (89%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap => plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap} (73%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap => plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap} (85%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/__snapshots__/header.test.js.snap => plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap} (88%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap => plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap} (99%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap => plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap} (93%)
 create mode 100644 src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.mocks.ts
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js => plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx} (75%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js => plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx} (77%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js => plugins/saved_objects_management/public/management_section/objects_table/components/header.test.tsx} (96%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js => plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx} (83%)
 create mode 100644 src/plugins/saved_objects_management/public/management_section/objects_table/components/index.ts
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js => plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx} (88%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js => plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx} (75%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js => plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx} (87%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js => plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx} (71%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/index.js => plugins/saved_objects_management/public/management_section/objects_table/index.ts} (93%)
 create mode 100644 src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.mocks.ts
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js => plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx} (58%)
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js => plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx} (73%)
 create mode 100644 src/plugins/saved_objects_management/public/management_section/types.ts
 create mode 100644 src/plugins/saved_objects_management/public/register_services.ts
 create mode 100644 src/plugins/saved_objects_management/public/services/action_service.mock.ts
 rename src/plugins/saved_objects_management/public/services/{action_registry.test.ts => action_service.test.ts} (69%)
 rename src/plugins/saved_objects_management/public/services/{action_registry.ts => action_service.ts} (56%)
 rename src/plugins/saved_objects_management/public/services/{action_registry.mock.ts => service_registry.mock.ts} (79%)
 create mode 100644 src/plugins/saved_objects_management/public/services/service_registry.ts
 rename src/plugins/saved_objects_management/public/services/{action_types.ts => types.ts} (100%)
 create mode 100644 src/plugins/saved_objects_management/public/types.ts
 rename src/{legacy/core_plugins/kibana/public/management/sections/objects/index.js => plugins/saved_objects_management/server/routes/get_allowed_types.ts} (61%)

diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts
index 0c4930592b233..959ffaa7e7e08 100644
--- a/src/core/public/mocks.ts
+++ b/src/core/public/mocks.ts
@@ -48,6 +48,7 @@ export { overlayServiceMock } from './overlays/overlay_service.mock';
 export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock';
 export { savedObjectsServiceMock } from './saved_objects/saved_objects_service.mock';
 export { scopedHistoryMock } from './application/scoped_history.mock';
+export { applicationServiceMock } from './application/application_service.mock';
 
 function createCoreSetupMock({
   basePath = '',
@@ -62,9 +63,8 @@ function createCoreSetupMock({
     application: applicationServiceMock.createSetupContract(),
     context: contextServiceMock.createSetupContract(),
     fatalErrors: fatalErrorsServiceMock.createSetupContract(),
-    getStartServices: jest.fn<Promise<[ReturnType<typeof createCoreStartMock>, object, any]>, []>(
-      () =>
-        Promise.resolve([createCoreStartMock({ basePath }), pluginStartDeps, pluginStartContract])
+    getStartServices: jest.fn<Promise<[ReturnType<typeof createCoreStartMock>, any, any]>, []>(() =>
+      Promise.resolve([createCoreStartMock({ basePath }), pluginStartDeps, pluginStartContract])
     ),
     http: httpServiceMock.createSetupContract({ basePath }),
     notifications: notificationServiceMock.createSetupContract(),
diff --git a/src/core/server/saved_objects/service/index.ts b/src/core/server/saved_objects/service/index.ts
index f44824238aa21..9f625b4732e26 100644
--- a/src/core/server/saved_objects/service/index.ts
+++ b/src/core/server/saved_objects/service/index.ts
@@ -36,7 +36,6 @@ export interface SavedObjectsLegacyService {
   getScopedSavedObjectsClient: SavedObjectsClientProvider['getClient'];
   SavedObjectsClient: typeof SavedObjectsClient;
   types: string[];
-  importAndExportableTypes: string[];
   schema: SavedObjectsSchema;
   getSavedObjectsRepository(...rest: any[]): any;
   importExport: {
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index a35bca7375286..37051da4b17da 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -2084,8 +2084,6 @@ export interface SavedObjectsLegacyService {
     // (undocumented)
     getScopedSavedObjectsClient: SavedObjectsClientProvider['getClient'];
     // (undocumented)
-    importAndExportableTypes: string[];
-    // (undocumented)
     importExport: {
         objectLimit: number;
         importSavedObjects(options: SavedObjectsImportOptions): Promise<SavedObjectsImportResponse>;
diff --git a/src/legacy/core_plugins/kibana/inject_vars.js b/src/legacy/core_plugins/kibana/inject_vars.js
index 76d1704907ab5..c3b906ee842e3 100644
--- a/src/legacy/core_plugins/kibana/inject_vars.js
+++ b/src/legacy/core_plugins/kibana/inject_vars.js
@@ -20,10 +20,7 @@
 export function injectVars(server) {
   const serverConfig = server.config();
 
-  const { importAndExportableTypes } = server.savedObjects;
-
   return {
-    importAndExportableTypes,
     autocompleteTerminateAfter: serverConfig.get('kibana.autocompleteTerminateAfter'),
     autocompleteTimeout: serverConfig.get('kibana.autocompleteTimeout'),
   };
diff --git a/src/legacy/core_plugins/kibana/public/index.ts b/src/legacy/core_plugins/kibana/public/index.ts
index a4fffc6eec26d..be22652ab2c1c 100644
--- a/src/legacy/core_plugins/kibana/public/index.ts
+++ b/src/legacy/core_plugins/kibana/public/index.ts
@@ -20,4 +20,4 @@
 export {
   ProcessedImportResponse,
   processImportResponse,
-} from './management/sections/objects/lib/process_import_response';
+} from '../../../../plugins/saved_objects_management/public/lib';
diff --git a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts b/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
index 705be68a141e7..587a372f91555 100644
--- a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
+++ b/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
@@ -17,66 +17,8 @@
  * under the License.
  */
 
-import _ from 'lodash';
-import { i18n } from '@kbn/i18n';
-import { npStart } from 'ui/new_platform';
-import { SavedObjectLoader } from '../../../../../plugins/saved_objects/public';
-import { createSavedSearchesLoader } from '../../../../../plugins/discover/public';
+import { npSetup } from 'ui/new_platform';
 
-/**
- * This registry is used for the editing mode of Saved Searches, Visualizations,
- * Dashboard and Time Lion saved objects.
- */
-interface SavedObjectRegistryEntry {
-  id: string;
-  service: SavedObjectLoader;
-  title: string;
-}
-
-export interface ISavedObjectsManagementRegistry {
-  register(service: SavedObjectRegistryEntry): void;
-  all(): SavedObjectRegistryEntry[];
-  get(id: string): SavedObjectRegistryEntry | undefined;
-}
-
-const registry: SavedObjectRegistryEntry[] = [];
-
-export const savedObjectManagementRegistry: ISavedObjectsManagementRegistry = {
-  register: (service: SavedObjectRegistryEntry) => {
-    registry.push(service);
-  },
-  all: () => {
-    return registry;
-  },
-  get: (id: string) => {
-    return _.find(registry, { id });
-  },
-};
-
-const services = {
-  savedObjectsClient: npStart.core.savedObjects.client,
-  indexPatterns: npStart.plugins.data.indexPatterns,
-  search: npStart.plugins.data.search,
-  chrome: npStart.core.chrome,
-  overlays: npStart.core.overlays,
-};
-
-savedObjectManagementRegistry.register({
-  id: 'savedVisualizations',
-  service: npStart.plugins.visualizations.savedVisualizationsLoader,
-  title: 'visualizations',
-});
-
-savedObjectManagementRegistry.register({
-  id: 'savedDashboards',
-  service: npStart.plugins.dashboard.getSavedDashboardLoader(),
-  title: i18n.translate('kbn.dashboard.savedDashboardsTitle', {
-    defaultMessage: 'dashboards',
-  }),
-});
+const registry = npSetup.plugins.savedObjectsManagement?.serviceRegistry;
 
-savedObjectManagementRegistry.register({
-  id: 'savedSearches',
-  service: createSavedSearchesLoader(services),
-  title: 'searches',
-});
+export const savedObjectManagementRegistry = registry!;
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index.js
index 54717ad003ade..adc1741f57263 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/index.js
@@ -17,5 +17,4 @@
  * under the License.
  */
 
-import './objects';
 import './index_patterns';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.html b/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.html
deleted file mode 100644
index 090fb7b636685..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<kbn-management-app section="kibana/objects">
-  <kbn-management-objects>
-    <div id="reactSavedObjectsTable"></div>
-  </kbn-management-objects>
-</kbn-management-app>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js
deleted file mode 100644
index c5901ca6ee6bf..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js
+++ /dev/null
@@ -1,104 +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 { savedObjectManagementRegistry } from '../../saved_object_registry';
-import objectIndexHTML from './_objects.html';
-import uiRoutes from 'ui/routes';
-import chrome from 'ui/chrome';
-import { uiModules } from 'ui/modules';
-import React from 'react';
-import { render, unmountComponentAtNode } from 'react-dom';
-import { ObjectsTable } from './components/objects_table';
-import { I18nContext } from 'ui/i18n';
-import { get } from 'lodash';
-import { npStart } from 'ui/new_platform';
-import { getIndexBreadcrumbs } from './breadcrumbs';
-
-const REACT_OBJECTS_TABLE_DOM_ELEMENT_ID = 'reactSavedObjectsTable';
-
-function updateObjectsTable($scope, $injector) {
-  const indexPatterns = npStart.plugins.data.indexPatterns;
-  const $http = $injector.get('$http');
-  const kbnUrl = $injector.get('kbnUrl');
-  const config = $injector.get('config');
-
-  const savedObjectsClient = npStart.core.savedObjects.client;
-  const services = savedObjectManagementRegistry.all().map(obj => obj.service);
-  const uiCapabilites = npStart.core.application.capabilities;
-
-  $scope.$$postDigest(() => {
-    const node = document.getElementById(REACT_OBJECTS_TABLE_DOM_ELEMENT_ID);
-    if (!node) {
-      return;
-    }
-
-    render(
-      <I18nContext>
-        <ObjectsTable
-          savedObjectsClient={savedObjectsClient}
-          confirmModalPromise={npStart.core.overlays.openConfirm}
-          services={services}
-          indexPatterns={indexPatterns}
-          $http={$http}
-          perPageConfig={config.get('savedObjects:perPage')}
-          basePath={chrome.getBasePath()}
-          newIndexPatternUrl={kbnUrl.eval('#/management/kibana/index_pattern')}
-          uiCapabilities={uiCapabilites}
-          goInspectObject={object => {
-            if (object.meta.editUrl) {
-              kbnUrl.change(object.meta.editUrl);
-              $scope.$apply();
-            }
-          }}
-          canGoInApp={object => {
-            const { inAppUrl } = object.meta;
-            return inAppUrl && get(uiCapabilites, inAppUrl.uiCapabilitiesPath);
-          }}
-        />
-      </I18nContext>,
-      node
-    );
-  });
-}
-
-function destroyObjectsTable() {
-  const node = document.getElementById(REACT_OBJECTS_TABLE_DOM_ELEMENT_ID);
-  node && unmountComponentAtNode(node);
-}
-
-uiRoutes
-  .when('/management/kibana/objects', {
-    template: objectIndexHTML,
-    k7Breadcrumbs: getIndexBreadcrumbs,
-    requireUICapability: 'management.kibana.objects',
-  })
-  .when('/management/kibana/objects/:service', {
-    redirectTo: '/management/kibana/objects',
-  });
-
-uiModules.get('apps/management').directive('kbnManagementObjects', function() {
-  return {
-    restrict: 'E',
-    controllerAs: 'managementObjectsController',
-    controller: function($scope, $injector) {
-      updateObjectsTable($scope, $injector);
-      $scope.$on('$destroy', destroyObjectsTable);
-    },
-  };
-});
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/_view.html b/src/legacy/core_plugins/kibana/public/management/sections/objects/_view.html
deleted file mode 100644
index 8bce0aabcd64a..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/_view.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<kbn-management-app section="kibana/objects" data-test-subj="savedObjectsEdit">
-  <kbn-management-objects-view>
-    <div id="reactSavedObjectsView"></div>
-  </kbn-management-objects-view>
-</kbn-management-app>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/_view.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/_view.js
deleted file mode 100644
index a847055b40015..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/_view.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import React from 'react';
-import { render, unmountComponentAtNode } from 'react-dom';
-import 'angular';
-import 'angular-elastic/elastic';
-import uiRoutes from 'ui/routes';
-import { uiModules } from 'ui/modules';
-import { I18nContext } from 'ui/i18n';
-import { npStart } from 'ui/new_platform';
-import objectViewHTML from './_view.html';
-import { getViewBreadcrumbs } from './breadcrumbs';
-import { savedObjectManagementRegistry } from '../../saved_object_registry';
-import { SavedObjectEdition } from './saved_object_view';
-
-const REACT_OBJECTS_VIEW_DOM_ELEMENT_ID = 'reactSavedObjectsView';
-
-uiRoutes.when('/management/kibana/objects/:service/:id', {
-  template: objectViewHTML,
-  k7Breadcrumbs: getViewBreadcrumbs,
-  requireUICapability: 'management.kibana.objects',
-});
-
-function createReactView($scope, $routeParams) {
-  const { service: serviceName, id: objectId, notFound } = $routeParams;
-
-  const { savedObjects, overlays, notifications, application } = npStart.core;
-
-  $scope.$$postDigest(() => {
-    const node = document.getElementById(REACT_OBJECTS_VIEW_DOM_ELEMENT_ID);
-    if (!node) {
-      return;
-    }
-
-    render(
-      <I18nContext>
-        <SavedObjectEdition
-          id={objectId}
-          serviceName={serviceName}
-          serviceRegistry={savedObjectManagementRegistry}
-          savedObjectsClient={savedObjects.client}
-          overlays={overlays}
-          notifications={notifications}
-          capabilities={application.capabilities}
-          notFoundType={notFound}
-        />
-      </I18nContext>,
-      node
-    );
-  });
-}
-
-function destroyReactView() {
-  const node = document.getElementById(REACT_OBJECTS_VIEW_DOM_ELEMENT_ID);
-  node && unmountComponentAtNode(node);
-}
-
-uiModules
-  .get('apps/management', ['monospaced.elastic'])
-  .directive('kbnManagementObjectsView', function() {
-    return {
-      restrict: 'E',
-      controller: function($scope, $routeParams) {
-        createReactView($scope, $routeParams);
-        $scope.$on('$destroy', destroyReactView);
-      },
-    };
-  });
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/breadcrumbs.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/breadcrumbs.js
deleted file mode 100644
index e9082bfeb680d..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/breadcrumbs.js
+++ /dev/null
@@ -1,50 +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 { MANAGEMENT_BREADCRUMB } from 'ui/management';
-import { i18n } from '@kbn/i18n';
-
-import { savedObjectManagementRegistry } from '../../saved_object_registry';
-
-export function getIndexBreadcrumbs() {
-  return [
-    MANAGEMENT_BREADCRUMB,
-    {
-      text: i18n.translate('kbn.management.savedObjects.indexBreadcrumb', {
-        defaultMessage: 'Saved objects',
-      }),
-      href: '#/management/kibana/objects',
-    },
-  ];
-}
-
-export function getViewBreadcrumbs($routeParams) {
-  const serviceObj = savedObjectManagementRegistry.get($routeParams.service);
-  const { service } = serviceObj;
-
-  return [
-    ...getIndexBreadcrumbs(),
-    {
-      text: i18n.translate('kbn.management.savedObjects.editBreadcrumb', {
-        defaultMessage: 'Edit {savedObjectType}',
-        values: { savedObjectType: service.type },
-      }),
-    },
-  ];
-}
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/index.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/index.js
deleted file mode 100644
index 601dea544361c..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-export { ObjectsTable } from './objects_table';
diff --git a/src/legacy/server/saved_objects/saved_objects_mixin.js b/src/legacy/server/saved_objects/saved_objects_mixin.js
index bcf766231dc9c..3e71e1989ae7a 100644
--- a/src/legacy/server/saved_objects/saved_objects_mixin.js
+++ b/src/legacy/server/saved_objects/saved_objects_mixin.js
@@ -78,13 +78,8 @@ export function savedObjectsMixin(kbnServer, server) {
 
   const provider = kbnServer.newPlatform.__internals.savedObjectsClientProvider;
 
-  const importAndExportableTypes = typeRegistry
-    .getImportableAndExportableTypes()
-    .map(type => type.name);
-
   const service = {
     types: visibleTypes,
-    importAndExportableTypes,
     SavedObjectsClient,
     SavedObjectsRepository,
     getSavedObjectsRepository: createRepository,
diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts
index ea1c27550867e..2d43cae79ac98 100644
--- a/src/plugins/data/public/mocks.ts
+++ b/src/plugins/data/public/mocks.ts
@@ -62,6 +62,7 @@ const createStartContract = (): Start => {
         },
       }),
       get: jest.fn().mockReturnValue(Promise.resolve({})),
+      clearCache: jest.fn(),
     } as unknown) as IndexPatternsContract,
   };
 };
diff --git a/src/plugins/discover/public/mocks.ts b/src/plugins/discover/public/mocks.ts
index bb05e3d412001..218c59b5db07b 100644
--- a/src/plugins/discover/public/mocks.ts
+++ b/src/plugins/discover/public/mocks.ts
@@ -37,6 +37,9 @@ const createStartContract = (): Start => {
     docViews: {
       DocViewer: jest.fn(() => null),
     },
+    savedSearches: {
+      createLoader: jest.fn(),
+    },
   };
   return startContract;
 };
diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts
index d2797586bfdfb..aa54823e6ec4d 100644
--- a/src/plugins/discover/public/plugin.ts
+++ b/src/plugins/discover/public/plugin.ts
@@ -21,12 +21,14 @@ import React from 'react';
 import { i18n } from '@kbn/i18n';
 import { auto } from 'angular';
 import { CoreSetup, Plugin } from 'kibana/public';
+import { SavedObjectLoader, SavedObjectKibanaServices } from '../../saved_objects/public';
 import { DocViewInput, DocViewInputFn, DocViewRenderProps } from './doc_views/doc_views_types';
 import { DocViewsRegistry } from './doc_views/doc_views_registry';
 import { DocViewTable } from './components/table/table';
 import { JsonCodeBlock } from './components/json_code_block/json_code_block';
 import { DocViewer } from './components/doc_viewer/doc_viewer';
 import { setDocViewsRegistry } from './services';
+import { createSavedSearchesLoader } from './saved_searches';
 
 import './index.scss';
 
@@ -62,6 +64,13 @@ export interface DiscoverStart {
      */
     DocViewer: React.ComponentType<DocViewRenderProps>;
   };
+  savedSearches: {
+    /**
+     * Create a {@link SavedObjectLoader | loader} to handle the saved searches type.
+     * @param services
+     */
+    createLoader(services: SavedObjectKibanaServices): SavedObjectLoader;
+  };
 }
 
 /**
@@ -105,6 +114,9 @@ export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
       docViews: {
         DocViewer,
       },
+      savedSearches: {
+        createLoader: createSavedSearchesLoader,
+      },
     };
   }
 }
diff --git a/src/plugins/management/public/mocks/index.ts b/src/plugins/management/public/mocks/index.ts
index 6099a2cc32afc..82789d3c3f55f 100644
--- a/src/plugins/management/public/mocks/index.ts
+++ b/src/plugins/management/public/mocks/index.ts
@@ -18,12 +18,21 @@
  */
 
 import { ManagementSetup, ManagementStart } from '../types';
+import { ManagementSection } from '../management_section';
+
+const createManagementSectionMock = (): jest.Mocked<PublicMethodsOf<ManagementSection>> => {
+  return {
+    registerApp: jest.fn(),
+    getApp: jest.fn(),
+    getAppsEnabled: jest.fn().mockReturnValue([]),
+  };
+};
 
 const createSetupContract = (): DeeplyMockedKeys<ManagementSetup> => ({
   sections: {
     register: jest.fn(),
-    getSection: jest.fn(),
-    getAllSections: jest.fn(),
+    getSection: jest.fn().mockReturnValue(createManagementSectionMock()),
+    getAllSections: jest.fn().mockReturnValue([]),
   },
 });
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/index.js b/src/plugins/saved_objects_management/common/index.ts
similarity index 89%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/index.js
rename to src/plugins/saved_objects_management/common/index.ts
index ac1e7bac06c87..67c3ae6d934ab 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/index.js
+++ b/src/plugins/saved_objects_management/common/index.ts
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-export { Header } from './header';
+export { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/types.ts b/src/plugins/saved_objects_management/common/types.ts
similarity index 74%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/types.ts
rename to src/plugins/saved_objects_management/common/types.ts
index 6a89142bc9798..be52d8e6486e2 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/types.ts
+++ b/src/plugins/saved_objects_management/common/types.ts
@@ -17,8 +17,12 @@
  * under the License.
  */
 
-import { SavedObject, SavedObjectReference } from 'src/core/public';
+import { SavedObject } from 'src/core/types';
 
+/**
+ * The metadata injected into a {@link SavedObject | saved object} when returning
+ * {@link SavedObjectWithMetadata | enhanced objects} from the plugin API endpoints.
+ */
 export interface SavedObjectMetadata {
   icon?: string;
   title?: string;
@@ -26,31 +30,19 @@ export interface SavedObjectMetadata {
   inAppUrl?: { path: string; uiCapabilitiesPath: string };
 }
 
+/**
+ * A {@link SavedObject | saved object} enhanced with meta properties used by the client-side plugin.
+ */
 export type SavedObjectWithMetadata<T = unknown> = SavedObject<T> & {
   meta: SavedObjectMetadata;
 };
 
+/**
+ * Represents a relation between two {@link SavedObject | saved object}
+ */
 export interface SavedObjectRelation {
   id: string;
   type: string;
   relationship: 'child' | 'parent';
   meta: SavedObjectMetadata;
 }
-
-export interface ObjectField {
-  type: FieldType;
-  name: string;
-  value: any;
-}
-
-export type FieldType = 'text' | 'number' | 'boolean' | 'array' | 'json';
-
-export interface FieldState {
-  value?: any;
-  invalid?: boolean;
-}
-
-export interface SubmittedFormData {
-  attributes: any;
-  references: SavedObjectReference[];
-}
diff --git a/src/plugins/saved_objects_management/kibana.json b/src/plugins/saved_objects_management/kibana.json
index e1f14b0e3c59d..22135ce4558ae 100644
--- a/src/plugins/saved_objects_management/kibana.json
+++ b/src/plugins/saved_objects_management/kibana.json
@@ -3,5 +3,6 @@
   "version": "kibana",
   "server": true,
   "ui": true,
-  "requiredPlugins": ["home"]
+  "requiredPlugins": ["home", "management", "data"],
+  "optionalPlugins": ["dashboard", "visualizations", "discover"]
 }
diff --git a/src/plugins/saved_objects_management/public/index.ts b/src/plugins/saved_objects_management/public/index.ts
index 7fb2f137d7d84..b20b320bc6645 100644
--- a/src/plugins/saved_objects_management/public/index.ts
+++ b/src/plugins/saved_objects_management/public/index.ts
@@ -22,10 +22,14 @@ import { SavedObjectsManagementPlugin } from './plugin';
 
 export { SavedObjectsManagementPluginSetup, SavedObjectsManagementPluginStart } from './plugin';
 export {
-  ISavedObjectsManagementActionRegistry,
+  SavedObjectsManagementActionServiceSetup,
+  SavedObjectsManagementActionServiceStart,
   SavedObjectsManagementAction,
   SavedObjectsManagementRecord,
+  ISavedObjectsManagementServiceRegistry,
+  SavedObjectsManagementServiceRegistryEntry,
 } from './services';
+export { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types';
 
 export function plugin(initializerContext: PluginInitializerContext) {
   return new SavedObjectsManagementPlugin();
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/case_conversion.test.ts b/src/plugins/saved_objects_management/public/lib/case_conversion.test.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/case_conversion.test.ts
rename to src/plugins/saved_objects_management/public/lib/case_conversion.test.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/case_conversion.ts b/src/plugins/saved_objects_management/public/lib/case_conversion.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/case_conversion.ts
rename to src/plugins/saved_objects_management/public/lib/case_conversion.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/create_field_list.test.ts b/src/plugins/saved_objects_management/public/lib/create_field_list.test.ts
similarity index 96%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/create_field_list.test.ts
rename to src/plugins/saved_objects_management/public/lib/create_field_list.test.ts
index 345716f91ea88..e7d6754ac4d05 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/create_field_list.test.ts
+++ b/src/plugins/saved_objects_management/public/lib/create_field_list.test.ts
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-import { SimpleSavedObject, SavedObjectReference } from '../../../../../../../../core/public';
-import { savedObjectsServiceMock } from '../../../../../../../../core/public/mocks';
+import { SimpleSavedObject, SavedObjectReference } from '../../../../core/public';
+import { savedObjectsServiceMock } from '../../../../core/public/mocks';
 import { createFieldList } from './create_field_list';
 
 const savedObjectClientMock = savedObjectsServiceMock.createStartContract().client;
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/create_field_list.ts b/src/plugins/saved_objects_management/public/lib/create_field_list.ts
similarity index 92%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/create_field_list.ts
rename to src/plugins/saved_objects_management/public/lib/create_field_list.ts
index 88a1184d5d70f..5d87c11a87198 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/create_field_list.ts
+++ b/src/plugins/saved_objects_management/public/lib/create_field_list.ts
@@ -18,10 +18,10 @@
  */
 
 import { forOwn, indexBy, isNumber, isBoolean, isPlainObject, isString } from 'lodash';
-import { SimpleSavedObject } from '../../../../../../../../core/public';
-import { castEsToKbnFieldTypeName } from '../../../../../../../../plugins/data/public';
-import { ObjectField } from '../types';
-import { SavedObjectLoader } from '../../../../../../../../plugins/saved_objects/public';
+import { SimpleSavedObject } from '../../../../core/public';
+import { castEsToKbnFieldTypeName } from '../../../data/public';
+import { ObjectField } from '../management_section/types';
+import { SavedObjectLoader } from '../../../saved_objects/public';
 
 const maxRecursiveIterations = 20;
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/extract_export_details.test.ts b/src/plugins/saved_objects_management/public/lib/extract_export_details.test.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/extract_export_details.test.ts
rename to src/plugins/saved_objects_management/public/lib/extract_export_details.test.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/extract_export_details.ts b/src/plugins/saved_objects_management/public/lib/extract_export_details.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/extract_export_details.ts
rename to src/plugins/saved_objects_management/public/lib/extract_export_details.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.ts b/src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts
similarity index 89%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.ts
rename to src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts
index d3e527b9f96b7..e0f005fab2a3b 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.ts
+++ b/src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts
@@ -17,16 +17,15 @@
  * under the License.
  */
 
-import { kfetch } from 'ui/kfetch';
+import { HttpStart } from 'src/core/public';
 
 export async function fetchExportByTypeAndSearch(
+  http: HttpStart,
   types: string[],
   search: string | undefined,
   includeReferencesDeep: boolean = false
 ): Promise<Blob> {
-  return await kfetch({
-    method: 'POST',
-    pathname: '/api/saved_objects/_export',
+  return http.post('/api/saved_objects/_export', {
     body: JSON.stringify({
       type: types,
       search,
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_objects.ts b/src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts
similarity index 89%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_objects.ts
rename to src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts
index 744f8ef38af47..745d3758371a3 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_objects.ts
+++ b/src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts
@@ -17,15 +17,14 @@
  * under the License.
  */
 
-import { kfetch } from 'ui/kfetch';
+import { HttpStart } from 'src/core/public';
 
 export async function fetchExportObjects(
+  http: HttpStart,
   objects: any[],
   includeReferencesDeep: boolean = false
 ): Promise<Blob> {
-  return await kfetch({
-    method: 'POST',
-    pathname: '/api/saved_objects/_export',
+  return http.post('/api/saved_objects/_export', {
     body: JSON.stringify({
       objects,
       includeReferencesDeep,
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/find_objects.ts b/src/plugins/saved_objects_management/public/lib/find_objects.ts
similarity index 57%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/find_objects.ts
rename to src/plugins/saved_objects_management/public/lib/find_objects.ts
index 24e08f0524f62..5a77d3ae2f663 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/find_objects.ts
+++ b/src/plugins/saved_objects_management/public/lib/find_objects.ts
@@ -17,16 +17,27 @@
  * under the License.
  */
 
-import { kfetch } from 'ui/kfetch';
-import { SavedObjectsFindOptions } from 'src/core/public';
+import { HttpStart, SavedObjectsFindOptions } from 'src/core/public';
 import { keysToCamelCaseShallow } from './case_conversion';
+import { SavedObjectWithMetadata } from '../types';
 
-export async function findObjects(findOptions: SavedObjectsFindOptions) {
-  const response = await kfetch({
-    method: 'GET',
-    pathname: '/api/kibana/management/saved_objects/_find',
-    query: findOptions as Record<string, any>,
-  });
+interface SavedObjectsFindResponse {
+  total: number;
+  page: number;
+  perPage: number;
+  savedObjects: SavedObjectWithMetadata[];
+}
+
+export async function findObjects(
+  http: HttpStart,
+  findOptions: SavedObjectsFindOptions
+): Promise<SavedObjectsFindResponse> {
+  const response = await http.get<Record<string, any>>(
+    '/api/kibana/management/saved_objects/_find',
+    {
+      query: findOptions as Record<string, any>,
+    }
+  );
 
-  return keysToCamelCaseShallow(response);
+  return keysToCamelCaseShallow(response) as SavedObjectsFindResponse;
 }
diff --git a/src/plugins/saved_objects_management/public/lib/get_allowed_types.ts b/src/plugins/saved_objects_management/public/lib/get_allowed_types.ts
new file mode 100644
index 0000000000000..7d952ebf2ca14
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/lib/get_allowed_types.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 { HttpStart } from 'src/core/public';
+
+interface GetAllowedTypesResponse {
+  types: string[];
+}
+
+export async function getAllowedTypes(http: HttpStart) {
+  const response = await http.get<GetAllowedTypesResponse>(
+    '/api/kibana/management/saved_objects/_allowed_types'
+  );
+  return response.types;
+}
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_default_title.ts b/src/plugins/saved_objects_management/public/lib/get_default_title.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_default_title.ts
rename to src/plugins/saved_objects_management/public/lib/get_default_title.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_relationships.test.ts b/src/plugins/saved_objects_management/public/lib/get_relationships.test.ts
similarity index 67%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_relationships.test.ts
rename to src/plugins/saved_objects_management/public/lib/get_relationships.test.ts
index b45b51b4de293..d79447378dde5 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_relationships.test.ts
+++ b/src/plugins/saved_objects_management/public/lib/get_relationships.test.ts
@@ -17,44 +17,43 @@
  * under the License.
  */
 
+import { httpServiceMock } from '../../../../core/public/mocks';
 import { getRelationships } from './get_relationships';
 
 describe('getRelationships', () => {
-  it('should make an http request', async () => {
-    const $http = jest.fn() as any;
-    const basePath = 'test';
+  let httpMock: ReturnType<typeof httpServiceMock.createSetupContract>;
 
-    await getRelationships('dashboard', '1', ['search', 'index-pattern'], $http, basePath);
-    expect($http.mock.calls.length).toBe(1);
+  beforeEach(() => {
+    httpMock = httpServiceMock.createSetupContract();
+  });
+
+  it('should make an http request', async () => {
+    await getRelationships(httpMock, 'dashboard', '1', ['search', 'index-pattern']);
+    expect(httpMock.get).toHaveBeenCalledTimes(1);
   });
 
   it('should handle successful responses', async () => {
-    const $http = jest.fn().mockImplementation(() => ({ data: [1, 2] })) as any;
-    const basePath = 'test';
-
-    const response = await getRelationships(
-      'dashboard',
-      '1',
-      ['search', 'index-pattern'],
-      $http,
-      basePath
-    );
+    httpMock.get.mockResolvedValue([1, 2]);
+
+    const response = await getRelationships(httpMock, 'dashboard', '1', [
+      'search',
+      'index-pattern',
+    ]);
     expect(response).toEqual([1, 2]);
   });
 
   it('should handle errors', async () => {
-    const $http = jest.fn().mockImplementation(() => {
+    httpMock.get.mockImplementation(() => {
       const err = new Error();
       (err as any).data = {
         error: 'Test error',
         statusCode: 500,
       };
       throw err;
-    }) as any;
-    const basePath = 'test';
+    });
 
     await expect(
-      getRelationships('dashboard', '1', ['search', 'index-pattern'], $http, basePath)
+      getRelationships(httpMock, 'dashboard', '1', ['search', 'index-pattern'])
     ).rejects.toThrowErrorMatchingInlineSnapshot(`"Test error"`);
   });
 });
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_relationships.ts b/src/plugins/saved_objects_management/public/lib/get_relationships.ts
similarity index 67%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_relationships.ts
rename to src/plugins/saved_objects_management/public/lib/get_relationships.ts
index 07bdf2db68fa2..bf2e651aa6593 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_relationships.ts
+++ b/src/plugins/saved_objects_management/public/lib/get_relationships.ts
@@ -17,36 +17,30 @@
  * under the License.
  */
 
-import { IHttpService } from 'angular';
+import { HttpStart } from 'src/core/public';
 import { get } from 'lodash';
 import { SavedObjectRelation } from '../types';
 
 export async function getRelationships(
+  http: HttpStart,
   type: string,
   id: string,
-  savedObjectTypes: string[],
-  $http: IHttpService,
-  basePath: string
+  savedObjectTypes: string[]
 ): Promise<SavedObjectRelation[]> {
-  const url = `${basePath}/api/kibana/management/saved_objects/relationships/${encodeURIComponent(
+  const url = `/api/kibana/management/saved_objects/relationships/${encodeURIComponent(
     type
   )}/${encodeURIComponent(id)}`;
-  const options = {
-    method: 'GET',
-    url,
-    params: {
-      savedObjectTypes,
-    },
-  };
-
   try {
-    const response = await $http<SavedObjectRelation[]>(options);
-    return response?.data;
-  } catch (resp) {
-    const respBody = get(resp, 'data', {}) as any;
-    const err = new Error(respBody.message || respBody.error || `${resp.status} Response`);
+    return await http.get<SavedObjectRelation[]>(url, {
+      query: {
+        savedObjectTypes,
+      },
+    });
+  } catch (respError) {
+    const respBody = get(respError, 'data', {}) as any;
+    const err = new Error(respBody.message || respBody.error || `${respError.status} Response`);
 
-    (err as any).statusCode = respBody.statusCode || resp.status;
+    (err as any).statusCode = respBody.statusCode || respError.status;
     (err as any).body = respBody;
 
     throw err;
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_saved_object_counts.ts b/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts
similarity index 72%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_saved_object_counts.ts
rename to src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts
index d4dda1190bc43..dcf59142e73e3 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_saved_object_counts.ts
+++ b/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts
@@ -17,18 +17,15 @@
  * under the License.
  */
 
-import { IHttpService } from 'angular';
-import chrome from 'ui/chrome';
+import { HttpStart } from 'src/core/public';
 
-const apiBase = chrome.addBasePath('/api/kibana/management/saved_objects/scroll');
 export async function getSavedObjectCounts(
-  $http: IHttpService,
+  http: HttpStart,
   typesToInclude: string[],
-  searchString: string
+  searchString?: string
 ): Promise<Record<string, number>> {
-  const results = await $http.post<Record<string, number>>(`${apiBase}/counts`, {
-    typesToInclude,
-    searchString,
-  });
-  return results.data;
+  return await http.post<Record<string, number>>(
+    `/api/kibana/management/saved_objects/scroll/counts`,
+    { body: JSON.stringify({ typesToInclude, searchString }) }
+  );
 }
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_saved_object_label.ts b/src/plugins/saved_objects_management/public/lib/get_saved_object_label.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/get_saved_object_label.ts
rename to src/plugins/saved_objects_management/public/lib/get_saved_object_label.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_file.ts b/src/plugins/saved_objects_management/public/lib/import_file.ts
similarity index 75%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_file.ts
rename to src/plugins/saved_objects_management/public/lib/import_file.ts
index 9bd5fbeed3a4c..96263452253ba 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_file.ts
+++ b/src/plugins/saved_objects_management/public/lib/import_file.ts
@@ -17,14 +17,18 @@
  * under the License.
  */
 
-import { kfetch } from 'ui/kfetch';
+import { HttpStart, SavedObjectsImportError } from 'src/core/public';
 
-export async function importFile(file: Blob, overwriteAll: boolean = false) {
+interface ImportResponse {
+  success: boolean;
+  successCount: number;
+  errors?: SavedObjectsImportError[];
+}
+
+export async function importFile(http: HttpStart, file: File, overwriteAll: boolean = false) {
   const formData = new FormData();
   formData.append('file', file);
-  return await kfetch({
-    method: 'POST',
-    pathname: '/api/saved_objects/_import',
+  return await http.post<ImportResponse>('/api/saved_objects/_import', {
     body: formData,
     headers: {
       // Important to be undefined, it forces proper headers to be set for FormData
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_legacy_file.test.ts b/src/plugins/saved_objects_management/public/lib/import_legacy_file.test.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_legacy_file.test.ts
rename to src/plugins/saved_objects_management/public/lib/import_legacy_file.test.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_legacy_file.ts b/src/plugins/saved_objects_management/public/lib/import_legacy_file.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/import_legacy_file.ts
rename to src/plugins/saved_objects_management/public/lib/import_legacy_file.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/in_app_url.test.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts
similarity index 98%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/in_app_url.test.ts
rename to src/plugins/saved_objects_management/public/lib/in_app_url.test.ts
index c0d6716391a1f..09e08e6ec333b 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/in_app_url.test.ts
+++ b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { Capabilities } from '../../../../../../../../core/public';
+import { Capabilities } from '../../../../core/public';
 import { canViewInApp } from './in_app_url';
 
 const createCapabilities = (sections: Record<string, any>): Capabilities => {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/in_app_url.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/in_app_url.ts
rename to src/plugins/saved_objects_management/public/lib/in_app_url.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.ts b/src/plugins/saved_objects_management/public/lib/index.ts
similarity index 94%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.ts
rename to src/plugins/saved_objects_management/public/lib/index.ts
index ecdfa6549a54e..7021744095651 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.ts
+++ b/src/plugins/saved_objects_management/public/lib/index.ts
@@ -43,3 +43,5 @@ export {
 export { getDefaultTitle } from './get_default_title';
 export { findObjects } from './find_objects';
 export { extractExportDetails, SavedObjectsExportResultDetails } from './extract_export_details';
+export { createFieldList } from './create_field_list';
+export { getAllowedTypes } from './get_allowed_types';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/log_legacy_import.ts b/src/plugins/saved_objects_management/public/lib/log_legacy_import.ts
similarity index 81%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/log_legacy_import.ts
rename to src/plugins/saved_objects_management/public/lib/log_legacy_import.ts
index 9bbafe3e69c98..9ec3c85b91c22 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/log_legacy_import.ts
+++ b/src/plugins/saved_objects_management/public/lib/log_legacy_import.ts
@@ -17,11 +17,8 @@
  * under the License.
  */
 
-import { kfetch } from 'ui/kfetch';
+import { HttpStart } from 'src/core/public';
 
-export async function logLegacyImport() {
-  return await kfetch({
-    method: 'POST',
-    pathname: '/api/saved_objects/_log_legacy_import',
-  });
+export async function logLegacyImport(http: HttpStart) {
+  return http.post('/api/saved_objects/_log_legacy_import');
 }
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/numeric.ts b/src/plugins/saved_objects_management/public/lib/numeric.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/numeric.ts
rename to src/plugins/saved_objects_management/public/lib/numeric.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/parse_query.test.ts b/src/plugins/saved_objects_management/public/lib/parse_query.test.ts
similarity index 92%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/parse_query.test.ts
rename to src/plugins/saved_objects_management/public/lib/parse_query.test.ts
index 77b34eccd9c6f..f62234eaf4e94 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/parse_query.test.ts
+++ b/src/plugins/saved_objects_management/public/lib/parse_query.test.ts
@@ -25,6 +25,6 @@ describe('getQueryText', () => {
       getTermClauses: () => [{ value: 'foo' }, { value: 'bar' }],
       getFieldClauses: () => [{ value: 'lala' }, { value: 'lolo' }],
     };
-    expect(parseQuery({ ast })).toEqual({ queryText: 'foo bar', visibleTypes: 'lala' });
+    expect(parseQuery({ ast } as any)).toEqual({ queryText: 'foo bar', visibleTypes: 'lala' });
   });
 });
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/parse_query.ts b/src/plugins/saved_objects_management/public/lib/parse_query.ts
similarity index 77%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/parse_query.ts
rename to src/plugins/saved_objects_management/public/lib/parse_query.ts
index 9b33deedafd95..f5b7b69ea049c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/parse_query.ts
+++ b/src/plugins/saved_objects_management/public/lib/parse_query.ts
@@ -17,9 +17,16 @@
  * under the License.
  */
 
-export function parseQuery(query: any) {
-  let queryText;
-  let visibleTypes;
+import { Query } from '@elastic/eui';
+
+interface ParsedQuery {
+  queryText?: string;
+  visibleTypes?: string[];
+}
+
+export function parseQuery(query: Query): ParsedQuery {
+  let queryText: string | undefined;
+  let visibleTypes: string[] | undefined;
 
   if (query) {
     if (query.ast.getTermClauses().length) {
@@ -29,7 +36,7 @@ export function parseQuery(query: any) {
         .join(' ');
     }
     if (query.ast.getFieldClauses('type')) {
-      visibleTypes = query.ast.getFieldClauses('type')[0].value;
+      visibleTypes = query.ast.getFieldClauses('type')[0].value as string[];
     }
   }
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/process_import_response.test.ts b/src/plugins/saved_objects_management/public/lib/process_import_response.test.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/process_import_response.test.ts
rename to src/plugins/saved_objects_management/public/lib/process_import_response.test.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/process_import_response.ts b/src/plugins/saved_objects_management/public/lib/process_import_response.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/process_import_response.ts
rename to src/plugins/saved_objects_management/public/lib/process_import_response.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_import_errors.test.ts b/src/plugins/saved_objects_management/public/lib/resolve_import_errors.test.ts
similarity index 90%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_import_errors.test.ts
rename to src/plugins/saved_objects_management/public/lib/resolve_import_errors.test.ts
index b94b0a9d1291f..86eebad7ae787 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_import_errors.test.ts
+++ b/src/plugins/saved_objects_management/public/lib/resolve_import_errors.test.ts
@@ -17,14 +17,10 @@
  * under the License.
  */
 
-jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
-
 import { SavedObjectsImportUnknownError } from 'src/core/public';
-import { kfetch } from 'ui/kfetch';
+import { httpServiceMock } from '../../../../core/public/mocks';
 import { resolveImportErrors } from './resolve_import_errors';
 
-const kfetchMock = kfetch as jest.Mock;
-
 function getFormData(form: Map<string, any>) {
   const formData: Record<string, any> = {};
   for (const [key, val] of form.entries()) {
@@ -39,13 +35,20 @@ function getFormData(form: Map<string, any>) {
 
 describe('resolveImportErrors', () => {
   const getConflictResolutions = jest.fn();
+  let httpMock: ReturnType<typeof httpServiceMock.createSetupContract>;
 
   beforeEach(() => {
+    httpMock = httpServiceMock.createSetupContract();
     jest.resetAllMocks();
   });
 
+  const extractBodyFromCall = (index: number): Map<string, any> => {
+    return (httpMock.post.mock.calls[index] as any)[1].body;
+  };
+
   test('works with empty import failures', async () => {
     const result = await resolveImportErrors({
+      http: httpMock,
       getConflictResolutions,
       state: {
         importCount: 0,
@@ -62,6 +65,7 @@ Object {
 
   test(`doesn't retry if only unknown failures are passed in`, async () => {
     const result = await resolveImportErrors({
+      http: httpMock,
       getConflictResolutions,
       state: {
         importCount: 0,
@@ -98,7 +102,7 @@ Object {
   });
 
   test('resolves conflicts', async () => {
-    kfetchMock.mockResolvedValueOnce({
+    httpMock.post.mockResolvedValueOnce({
       success: true,
       successCount: 1,
     });
@@ -107,6 +111,7 @@ Object {
       'a:2': false,
     });
     const result = await resolveImportErrors({
+      http: httpMock,
       getConflictResolutions,
       state: {
         importCount: 0,
@@ -139,7 +144,8 @@ Object {
   "status": "success",
 }
 `);
-    const formData = getFormData(kfetchMock.mock.calls[0][0].body);
+
+    const formData = getFormData(extractBodyFromCall(0));
     expect(formData).toMatchInlineSnapshot(`
 Object {
   "file": "undefined",
@@ -156,12 +162,13 @@ Object {
   });
 
   test('resolves missing references', async () => {
-    kfetchMock.mockResolvedValueOnce({
+    httpMock.post.mockResolvedValueOnce({
       success: true,
       successCount: 2,
     });
     getConflictResolutions.mockResolvedValueOnce({});
     const result = await resolveImportErrors({
+      http: httpMock,
       getConflictResolutions,
       state: {
         importCount: 0,
@@ -203,7 +210,7 @@ Object {
   "status": "success",
 }
 `);
-    const formData = getFormData(kfetchMock.mock.calls[0][0].body);
+    const formData = getFormData(extractBodyFromCall(0));
     expect(formData).toMatchInlineSnapshot(`
 Object {
   "file": "undefined",
@@ -232,6 +239,7 @@ Object {
   test(`doesn't resolve missing references if newIndexPatternId isn't defined`, async () => {
     getConflictResolutions.mockResolvedValueOnce({});
     const result = await resolveImportErrors({
+      http: httpMock,
       getConflictResolutions,
       state: {
         importCount: 0,
@@ -276,7 +284,7 @@ Object {
   });
 
   test('handles missing references then conflicts on the same errored objects', async () => {
-    kfetchMock.mockResolvedValueOnce({
+    httpMock.post.mockResolvedValueOnce({
       success: false,
       successCount: 0,
       errors: [
@@ -289,7 +297,7 @@ Object {
         },
       ],
     });
-    kfetchMock.mockResolvedValueOnce({
+    httpMock.post.mockResolvedValueOnce({
       success: true,
       successCount: 1,
     });
@@ -298,6 +306,7 @@ Object {
       'a:1': true,
     });
     const result = await resolveImportErrors({
+      http: httpMock,
       getConflictResolutions,
       state: {
         importCount: 0,
@@ -334,7 +343,7 @@ Object {
   "status": "success",
 }
 `);
-    const formData1 = getFormData(kfetchMock.mock.calls[0][0].body);
+    const formData1 = getFormData(extractBodyFromCall(0));
     expect(formData1).toMatchInlineSnapshot(`
 Object {
   "file": "undefined",
@@ -354,7 +363,7 @@ Object {
   ],
 }
 `);
-    const formData2 = getFormData(kfetchMock.mock.calls[1][0].body);
+    const formData2 = getFormData(extractBodyFromCall(1));
     expect(formData2).toMatchInlineSnapshot(`
 Object {
   "file": "undefined",
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_import_errors.ts b/src/plugins/saved_objects_management/public/lib/resolve_import_errors.ts
similarity index 95%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_import_errors.ts
rename to src/plugins/saved_objects_management/public/lib/resolve_import_errors.ts
index dcc282402147d..0aea7114bad1c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_import_errors.ts
+++ b/src/plugins/saved_objects_management/public/lib/resolve_import_errors.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { kfetch } from 'ui/kfetch';
+import { HttpStart } from 'src/core/public';
 import { FailedImport } from './process_import_response';
 
 interface RetryObject {
@@ -27,13 +27,11 @@ interface RetryObject {
   replaceReferences?: any[];
 }
 
-async function callResolveImportErrorsApi(file: File, retries: any) {
+async function callResolveImportErrorsApi(http: HttpStart, file: File, retries: any) {
   const formData = new FormData();
   formData.append('file', file);
   formData.append('retries', JSON.stringify(retries));
-  return await kfetch({
-    method: 'POST',
-    pathname: '/api/saved_objects/_resolve_import_errors',
+  return http.post<any>('/api/saved_objects/_resolve_import_errors', {
     headers: {
       // Important to be undefined, it forces proper headers to be set for FormData
       'Content-Type': undefined,
@@ -100,9 +98,11 @@ function mapImportFailureToRetryObject({
 }
 
 export async function resolveImportErrors({
+  http,
   getConflictResolutions,
   state,
 }: {
+  http: HttpStart;
   getConflictResolutions: (objects: any[]) => Promise<Record<string, boolean>>;
   state: { importCount: number; failedImports?: FailedImport[] } & Record<string, any>;
 }) {
@@ -170,7 +170,7 @@ export async function resolveImportErrors({
     }
 
     // Call API
-    const response = await callResolveImportErrorsApi(file, retries);
+    const response = await callResolveImportErrorsApi(http, file, retries);
     successImportCount += response.successCount;
     importFailures = [];
     for (const { error, ...obj } of response.errors || []) {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts b/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.test.ts
similarity index 98%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts
rename to src/plugins/saved_objects_management/public/lib/resolve_saved_objects.test.ts
index dc6d2643145ff..23c2b75169555 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.test.ts
+++ b/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.test.ts
@@ -23,11 +23,8 @@ import {
   saveObjects,
   saveObject,
 } from './resolve_saved_objects';
-import {
-  SavedObject,
-  SavedObjectLoader,
-} from '../../../../../../../../plugins/saved_objects/public';
-import { IndexPatternsContract } from '../../../../../../../../plugins/data/public';
+import { SavedObject, SavedObjectLoader } from '../../../saved_objects/public';
+import { IndexPatternsContract } from '../../../data/public';
 
 class SavedObjectNotFound extends Error {
   constructor(options: Record<string, any>) {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts b/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts
similarity index 94%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts
rename to src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts
index d9473367f7502..15e03ed39d88c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.ts
+++ b/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts
@@ -20,15 +20,8 @@
 import { i18n } from '@kbn/i18n';
 import { cloneDeep } from 'lodash';
 import { OverlayStart, SavedObjectReference } from 'src/core/public';
-import {
-  SavedObject,
-  SavedObjectLoader,
-} from '../../../../../../../../plugins/saved_objects/public';
-import {
-  IndexPatternsContract,
-  IIndexPattern,
-  createSearchSource,
-} from '../../../../../../../../plugins/data/public';
+import { SavedObject, SavedObjectLoader } from '../../../saved_objects/public';
+import { IndexPatternsContract, IIndexPattern, createSearchSource } from '../../../data/public';
 
 type SavedObjectsRawDoc = Record<string, any>;
 
@@ -55,7 +48,7 @@ function addJsonFieldToIndexPattern(
       target[fieldName] = JSON.parse(sourceString);
     } catch (error) {
       throw new Error(
-        i18n.translate('kbn.management.objects.parsingFieldErrorMessage', {
+        i18n.translate('savedObjectsManagement.parsingFieldErrorMessage', {
           defaultMessage:
             'Error encountered parsing {fieldName} for index pattern {indexName}: {errorMessage}',
           values: {
@@ -103,18 +96,21 @@ async function importIndexPattern(
   if (!newId) {
     // We can override and we want to prompt for confirmation
     const isConfirmed = await openConfirm(
-      i18n.translate('kbn.management.indexPattern.confirmOverwriteLabel', {
+      i18n.translate('savedObjectsManagement.indexPattern.confirmOverwriteLabel', {
         values: { title },
         defaultMessage: "Are you sure you want to overwrite '{title}'?",
       }),
       {
-        title: i18n.translate('kbn.management.indexPattern.confirmOverwriteTitle', {
+        title: i18n.translate('savedObjectsManagement.indexPattern.confirmOverwriteTitle', {
           defaultMessage: 'Overwrite {type}?',
           values: { type },
         }),
-        confirmButtonText: i18n.translate('kbn.management.indexPattern.confirmOverwriteButton', {
-          defaultMessage: 'Overwrite',
-        }),
+        confirmButtonText: i18n.translate(
+          'savedObjectsManagement.indexPattern.confirmOverwriteButton',
+          {
+            defaultMessage: 'Overwrite',
+          }
+        ),
       }
     );
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/index.js b/src/plugins/saved_objects_management/public/management_section/index.ts
similarity index 93%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/index.js
rename to src/plugins/saved_objects_management/public/management_section/index.ts
index 522b1ce83a6b6..1bccb2102f3b4 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/index.js
+++ b/src/plugins/saved_objects_management/public/management_section/index.ts
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-export { Relationships } from './relationships';
+export { mountManagementSection } from './mount_section';
diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx
new file mode 100644
index 0000000000000..6f03f97079bb6
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx
@@ -0,0 +1,211 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { useEffect } from 'react';
+import ReactDOM from 'react-dom';
+import { HashRouter, Switch, Route, useParams, useLocation } from 'react-router-dom';
+import { parse } from 'query-string';
+import { get } from 'lodash';
+import { i18n } from '@kbn/i18n';
+import { I18nProvider } from '@kbn/i18n/react';
+import { CoreSetup, CoreStart, ChromeBreadcrumb, Capabilities } from 'src/core/public';
+import { ManagementAppMountParams } from '../../../management/public';
+import { DataPublicPluginStart } from '../../../data/public';
+import { StartDependencies, SavedObjectsManagementPluginStart } from '../plugin';
+import {
+  ISavedObjectsManagementServiceRegistry,
+  SavedObjectsManagementActionServiceStart,
+} from '../services';
+import { SavedObjectsTable } from './objects_table';
+import { SavedObjectEdition } from './object_view';
+import { getAllowedTypes } from './../lib';
+
+interface MountParams {
+  core: CoreSetup<StartDependencies, SavedObjectsManagementPluginStart>;
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
+  mountParams: ManagementAppMountParams;
+}
+
+let allowedObjectTypes: string[] | undefined;
+
+export const mountManagementSection = async ({
+  core,
+  mountParams,
+  serviceRegistry,
+}: MountParams) => {
+  const [coreStart, { data }, pluginStart] = await core.getStartServices();
+  const { element, basePath, setBreadcrumbs } = mountParams;
+  if (allowedObjectTypes === undefined) {
+    allowedObjectTypes = await getAllowedTypes(coreStart.http);
+  }
+
+  const capabilities = coreStart.application.capabilities;
+
+  ReactDOM.render(
+    <I18nProvider>
+      <HashRouter basename={basePath}>
+        <Switch>
+          <Route path={'/:service/:id'} exact={true}>
+            <RedirectToHomeIfUnauthorized capabilities={capabilities}>
+              <SavedObjectsEditionPage
+                coreStart={coreStart}
+                serviceRegistry={serviceRegistry}
+                setBreadcrumbs={setBreadcrumbs}
+              />
+            </RedirectToHomeIfUnauthorized>
+          </Route>
+          <Route path={'/'} exact={false}>
+            <RedirectToHomeIfUnauthorized capabilities={capabilities}>
+              <SavedObjectsTablePage
+                coreStart={coreStart}
+                dataStart={data}
+                serviceRegistry={serviceRegistry}
+                actionRegistry={pluginStart.actions}
+                allowedTypes={allowedObjectTypes}
+                setBreadcrumbs={setBreadcrumbs}
+              />
+            </RedirectToHomeIfUnauthorized>
+          </Route>
+        </Switch>
+      </HashRouter>
+    </I18nProvider>,
+    element
+  );
+
+  return () => {
+    ReactDOM.unmountComponentAtNode(element);
+  };
+};
+
+const RedirectToHomeIfUnauthorized: React.FunctionComponent<{
+  capabilities: Capabilities;
+}> = ({ children, capabilities }) => {
+  const allowed = capabilities?.management?.kibana?.objects ?? false;
+  if (!allowed) {
+    window.location.hash = '/home';
+    return null;
+  }
+  return children! as React.ReactElement;
+};
+
+const SavedObjectsEditionPage = ({
+  coreStart,
+  serviceRegistry,
+  setBreadcrumbs,
+}: {
+  coreStart: CoreStart;
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
+  setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void;
+}) => {
+  const { service: serviceName, id } = useParams<{ service: string; id: string }>();
+  const capabilities = coreStart.application.capabilities;
+
+  const { search } = useLocation();
+  const query = parse(search);
+  const service = serviceRegistry.get(serviceName);
+
+  useEffect(() => {
+    setBreadcrumbs([
+      {
+        text: i18n.translate('savedObjectsManagement.breadcrumb.index', {
+          defaultMessage: 'Saved objects',
+        }),
+        href: '#/management/kibana/objects',
+      },
+      {
+        text: i18n.translate('savedObjectsManagement.breadcrumb.edit', {
+          defaultMessage: 'Edit {savedObjectType}',
+          values: { savedObjectType: service?.service.type ?? 'object' },
+        }),
+      },
+    ]);
+  }, [setBreadcrumbs, service]);
+
+  return (
+    <SavedObjectEdition
+      id={id}
+      serviceName={serviceName}
+      serviceRegistry={serviceRegistry}
+      savedObjectsClient={coreStart.savedObjects.client}
+      overlays={coreStart.overlays}
+      notifications={coreStart.notifications}
+      capabilities={capabilities}
+      notFoundType={query.notFound as string}
+    />
+  );
+};
+
+const SavedObjectsTablePage = ({
+  coreStart,
+  dataStart,
+  allowedTypes,
+  serviceRegistry,
+  actionRegistry,
+  setBreadcrumbs,
+}: {
+  coreStart: CoreStart;
+  dataStart: DataPublicPluginStart;
+  allowedTypes: string[];
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
+  actionRegistry: SavedObjectsManagementActionServiceStart;
+  setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void;
+}) => {
+  const capabilities = coreStart.application.capabilities;
+  const itemsPerPage = coreStart.uiSettings.get<number>('savedObjects:perPage', 50);
+
+  useEffect(() => {
+    setBreadcrumbs([
+      {
+        text: i18n.translate('savedObjectsManagement.breadcrumb.index', {
+          defaultMessage: 'Saved objects',
+        }),
+        href: '#/management/kibana/objects',
+      },
+    ]);
+  }, [setBreadcrumbs]);
+
+  return (
+    <SavedObjectsTable
+      allowedTypes={allowedTypes}
+      serviceRegistry={serviceRegistry}
+      actionRegistry={actionRegistry}
+      savedObjectsClient={coreStart.savedObjects.client}
+      indexPatterns={dataStart.indexPatterns}
+      http={coreStart.http}
+      overlays={coreStart.overlays}
+      notifications={coreStart.notifications}
+      applications={coreStart.application}
+      perPageConfig={itemsPerPage}
+      goInspectObject={savedObject => {
+        const { editUrl } = savedObject.meta;
+        if (editUrl) {
+          // previously, kbnUrl.change(object.meta.editUrl); was used.
+          // using direct access to location.hash seems the only option for now,
+          // as using react-router-dom will prefix the url with the router's basename
+          // which should be ignored there.
+          window.location.hash = editUrl;
+        }
+      }}
+      canGoInApp={savedObject => {
+        const { inAppUrl } = savedObject.meta;
+        return inAppUrl ? get(capabilities, inAppUrl.uiCapabilitiesPath) : false;
+      }}
+    />
+  );
+};
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/header.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap
similarity index 96%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/header.test.tsx.snap
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap
index 7e1f7ea12b014..d56776c2be9d7 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/header.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap
@@ -23,7 +23,7 @@ exports[`Intro component renders correctly 1`] = `
             >
               <FormattedMessage
                 defaultMessage="Edit {title}"
-                id="kbn.management.objects.view.editItemTitle"
+                id="savedObjectsManagement.view.editItemTitle"
                 values={
                   Object {
                     "title": "search",
@@ -85,7 +85,7 @@ exports[`Intro component renders correctly 1`] = `
                         >
                           <FormattedMessage
                             defaultMessage="View {title}"
-                            id="kbn.management.objects.view.viewItemButtonLabel"
+                            id="savedObjectsManagement.view.viewItemButtonLabel"
                             values={
                               Object {
                                 "title": "search",
@@ -140,7 +140,7 @@ exports[`Intro component renders correctly 1`] = `
                         >
                           <FormattedMessage
                             defaultMessage="Delete {title}"
-                            id="kbn.management.objects.view.deleteItemButtonLabel"
+                            id="savedObjectsManagement.view.deleteItemButtonLabel"
                             values={
                               Object {
                                 "title": "search",
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/intro.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/intro.test.tsx.snap
similarity index 90%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/intro.test.tsx.snap
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/intro.test.tsx.snap
index 812031b4b363c..ff179401e6f71 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/intro.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/intro.test.tsx.snap
@@ -8,7 +8,7 @@ exports[`Intro component renders correctly 1`] = `
     title={
       <FormattedMessage
         defaultMessage="Proceed with caution!"
-        id="kbn.management.objects.view.howToModifyObjectTitle"
+        id="savedObjectsManagement.view.howToModifyObjectTitle"
         values={Object {}}
       />
     }
@@ -37,7 +37,7 @@ exports[`Intro component renders correctly 1`] = `
         >
           <FormattedMessage
             defaultMessage="Proceed with caution!"
-            id="kbn.management.objects.view.howToModifyObjectTitle"
+            id="savedObjectsManagement.view.howToModifyObjectTitle"
             values={Object {}}
           >
             Proceed with caution!
@@ -53,7 +53,7 @@ exports[`Intro component renders correctly 1`] = `
           <div>
             <FormattedMessage
               defaultMessage="Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be."
-              id="kbn.management.objects.view.howToModifyObjectDescription"
+              id="savedObjectsManagement.view.howToModifyObjectDescription"
               values={Object {}}
             >
               Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be.
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/not_found_errors.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap
similarity index 89%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/not_found_errors.test.tsx.snap
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap
index ac565a000813e..d5372fd5b18d9 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/__snapshots__/not_found_errors.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap
@@ -10,7 +10,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern type 1`] =
     title={
       <FormattedMessage
         defaultMessage="There is a problem with this saved object"
-        id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+        id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
         values={Object {}}
       />
     }
@@ -39,7 +39,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern type 1`] =
         >
           <FormattedMessage
             defaultMessage="There is a problem with this saved object"
-            id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+            id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
             values={Object {}}
           >
             There is a problem with this saved object
@@ -55,7 +55,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern type 1`] =
           <div>
             <FormattedMessage
               defaultMessage="The index pattern associated with this object no longer exists."
-              id="kbn.management.objects.view.indexPatternDoesNotExistErrorMessage"
+              id="savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage"
               values={Object {}}
             >
               The index pattern associated with this object no longer exists.
@@ -64,7 +64,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern type 1`] =
           <div>
             <FormattedMessage
               defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
-              id="kbn.management.objects.view.howToFixErrorDescription"
+              id="savedObjectsManagement.view.howToFixErrorDescription"
               values={Object {}}
             >
               If you know what this error means, go ahead and fix it — otherwise click the delete button above.
@@ -87,7 +87,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern-field type
     title={
       <FormattedMessage
         defaultMessage="There is a problem with this saved object"
-        id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+        id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
         values={Object {}}
       />
     }
@@ -116,7 +116,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern-field type
         >
           <FormattedMessage
             defaultMessage="There is a problem with this saved object"
-            id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+            id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
             values={Object {}}
           >
             There is a problem with this saved object
@@ -132,7 +132,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern-field type
           <div>
             <FormattedMessage
               defaultMessage="A field associated with this object no longer exists in the index pattern."
-              id="kbn.management.objects.view.fieldDoesNotExistErrorMessage"
+              id="savedObjectsManagement.view.fieldDoesNotExistErrorMessage"
               values={Object {}}
             >
               A field associated with this object no longer exists in the index pattern.
@@ -141,7 +141,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern-field type
           <div>
             <FormattedMessage
               defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
-              id="kbn.management.objects.view.howToFixErrorDescription"
+              id="savedObjectsManagement.view.howToFixErrorDescription"
               values={Object {}}
             >
               If you know what this error means, go ahead and fix it — otherwise click the delete button above.
@@ -164,7 +164,7 @@ exports[`NotFoundErrors component renders correctly for search type 1`] = `
     title={
       <FormattedMessage
         defaultMessage="There is a problem with this saved object"
-        id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+        id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
         values={Object {}}
       />
     }
@@ -193,7 +193,7 @@ exports[`NotFoundErrors component renders correctly for search type 1`] = `
         >
           <FormattedMessage
             defaultMessage="There is a problem with this saved object"
-            id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+            id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
             values={Object {}}
           >
             There is a problem with this saved object
@@ -209,7 +209,7 @@ exports[`NotFoundErrors component renders correctly for search type 1`] = `
           <div>
             <FormattedMessage
               defaultMessage="The saved search associated with this object no longer exists."
-              id="kbn.management.objects.view.savedSearchDoesNotExistErrorMessage"
+              id="savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage"
               values={Object {}}
             >
               The saved search associated with this object no longer exists.
@@ -218,7 +218,7 @@ exports[`NotFoundErrors component renders correctly for search type 1`] = `
           <div>
             <FormattedMessage
               defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
-              id="kbn.management.objects.view.howToFixErrorDescription"
+              id="savedObjectsManagement.view.howToFixErrorDescription"
               values={Object {}}
             >
               If you know what this error means, go ahead and fix it — otherwise click the delete button above.
@@ -241,7 +241,7 @@ exports[`NotFoundErrors component renders correctly for unknown type 1`] = `
     title={
       <FormattedMessage
         defaultMessage="There is a problem with this saved object"
-        id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+        id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
         values={Object {}}
       />
     }
@@ -270,7 +270,7 @@ exports[`NotFoundErrors component renders correctly for unknown type 1`] = `
         >
           <FormattedMessage
             defaultMessage="There is a problem with this saved object"
-            id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+            id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
             values={Object {}}
           >
             There is a problem with this saved object
@@ -287,7 +287,7 @@ exports[`NotFoundErrors component renders correctly for unknown type 1`] = `
           <div>
             <FormattedMessage
               defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
-              id="kbn.management.objects.view.howToFixErrorDescription"
+              id="savedObjectsManagement.view.howToFixErrorDescription"
               values={Object {}}
             >
               If you know what this error means, go ahead and fix it — otherwise click the delete button above.
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/field.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.test.tsx
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/field.test.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/field.test.tsx
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/field.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx
similarity index 97%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/field.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx
index 1ed0b57e400b8..1b69eb4240d68 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/field.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx
@@ -104,9 +104,9 @@ export class Field extends PureComponent<FieldProps> {
             id={this.fieldId}
             label={
               !!currentValue ? (
-                <FormattedMessage id="kbn.management.objects.field.onLabel" defaultMessage="On" />
+                <FormattedMessage id="savedObjectsManagement.field.onLabel" defaultMessage="On" />
               ) : (
-                <FormattedMessage id="kbn.management.objects.field.offLabel" defaultMessage="Off" />
+                <FormattedMessage id="savedObjectsManagement.field.offLabel" defaultMessage="Off" />
               )
             }
             checked={!!currentValue}
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/form.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/form.tsx
similarity index 89%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/form.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/form.tsx
index 7270d41eef529..04be7ee3ce207 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/form.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/form.tsx
@@ -29,15 +29,11 @@ import {
 import { cloneDeep, set } from 'lodash';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-import {
-  SimpleSavedObject,
-  SavedObjectsClientContract,
-} from '../../../../../../../../../core/public';
-
-import { SavedObjectLoader } from '../../../../../../../../../plugins/saved_objects/public';
+import { SimpleSavedObject, SavedObjectsClientContract } from '../../../../../../core/public';
+import { SavedObjectLoader } from '../../../../../saved_objects/public';
 import { Field } from './field';
 import { ObjectField, FieldState, SubmittedFormData } from '../../types';
-import { createFieldList } from '../../lib/create_field_list';
+import { createFieldList } from '../../../lib';
 
 interface FormProps {
   object: SimpleSavedObject;
@@ -96,7 +92,7 @@ export class Form extends Component<FormProps, FormState> {
             <EuiFlexItem grow={false}>
               <EuiButton
                 fill={true}
-                aria-label={i18n.translate('kbn.management.objects.view.saveButtonAriaLabel', {
+                aria-label={i18n.translate('savedObjectsManagement.view.saveButtonAriaLabel', {
                   defaultMessage: 'Save { title } object',
                   values: {
                     title: service.type,
@@ -107,7 +103,7 @@ export class Form extends Component<FormProps, FormState> {
                 data-test-subj="savedObjectEditSave"
               >
                 <FormattedMessage
-                  id="kbn.management.objects.view.saveButtonLabel"
+                  id="savedObjectsManagement.view.saveButtonLabel"
                   defaultMessage="Save { title } object"
                   values={{ title: service.type }}
                 />
@@ -117,14 +113,14 @@ export class Form extends Component<FormProps, FormState> {
 
           <EuiFlexItem grow={false}>
             <EuiButtonEmpty
-              aria-label={i18n.translate('kbn.management.objects.view.cancelButtonAriaLabel', {
+              aria-label={i18n.translate('savedObjectsManagement.view.cancelButtonAriaLabel', {
                 defaultMessage: 'Cancel',
               })}
               onClick={this.onCancel}
               data-test-subj="savedObjectEditCancel"
             >
               <FormattedMessage
-                id="kbn.management.objects.view.cancelButtonLabel"
+                id="savedObjectsManagement.view.cancelButtonLabel"
                 defaultMessage="Cancel"
               />
             </EuiButtonEmpty>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/header.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.test.tsx
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/header.test.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/header.test.tsx
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/header.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx
similarity index 92%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/header.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx
index 641493e0cbaa8..305d953c4990b 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/header.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx
@@ -52,7 +52,7 @@ export const Header = ({
           {canEdit ? (
             <h1>
               <FormattedMessage
-                id="kbn.management.objects.view.editItemTitle"
+                id="savedObjectsManagement.view.editItemTitle"
                 defaultMessage="Edit {title}"
                 values={{ title: type }}
               />
@@ -60,7 +60,7 @@ export const Header = ({
           ) : (
             <h1>
               <FormattedMessage
-                id="kbn.management.objects.view.viewItemTitle"
+                id="savedObjectsManagement.view.viewItemTitle"
                 defaultMessage="View {title}"
                 values={{ title: type }}
               />
@@ -79,7 +79,7 @@ export const Header = ({
                 data-test-subj="savedObjectEditViewInApp"
               >
                 <FormattedMessage
-                  id="kbn.management.objects.view.viewItemButtonLabel"
+                  id="savedObjectsManagement.view.viewItemButtonLabel"
                   defaultMessage="View {title}"
                   values={{ title: type }}
                 />
@@ -96,7 +96,7 @@ export const Header = ({
                 data-test-subj="savedObjectEditDelete"
               >
                 <FormattedMessage
-                  id="kbn.management.objects.view.deleteItemButtonLabel"
+                  id="savedObjectsManagement.view.deleteItemButtonLabel"
                   defaultMessage="Delete {title}"
                   values={{ title: type }}
                 />
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/index.ts b/src/plugins/saved_objects_management/public/management_section/object_view/components/index.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/index.ts
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/index.ts
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/intro.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.test.tsx
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/intro.test.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/intro.test.tsx
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/intro.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx
similarity index 92%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/intro.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx
index 098ad71345d49..920a5fcbcb02e 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/intro.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx
@@ -26,7 +26,7 @@ export const Intro = () => {
     <EuiCallOut
       title={
         <FormattedMessage
-          id="kbn.management.objects.view.howToModifyObjectTitle"
+          id="savedObjectsManagement.view.howToModifyObjectTitle"
           defaultMessage="Proceed with caution!"
         />
       }
@@ -35,7 +35,7 @@ export const Intro = () => {
     >
       <div>
         <FormattedMessage
-          id="kbn.management.objects.view.howToModifyObjectDescription"
+          id="savedObjectsManagement.view.howToModifyObjectDescription"
           defaultMessage="Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn&rsquo;t be."
         />
       </div>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/not_found_errors.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.test.tsx
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/not_found_errors.test.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.test.tsx
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/not_found_errors.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx
similarity index 87%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/not_found_errors.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx
index c3d18855f6c9a..1a63f7eaf4819 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/object_view/not_found_errors.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx
@@ -31,21 +31,21 @@ export const NotFoundErrors = ({ type }: NotFoundErrors) => {
       case 'search':
         return (
           <FormattedMessage
-            id="kbn.management.objects.view.savedSearchDoesNotExistErrorMessage"
+            id="savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage"
             defaultMessage="The saved search associated with this object no longer exists."
           />
         );
       case 'index-pattern':
         return (
           <FormattedMessage
-            id="kbn.management.objects.view.indexPatternDoesNotExistErrorMessage"
+            id="savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage"
             defaultMessage="The index pattern associated with this object no longer exists."
           />
         );
       case 'index-pattern-field':
         return (
           <FormattedMessage
-            id="kbn.management.objects.view.fieldDoesNotExistErrorMessage"
+            id="savedObjectsManagement.view.fieldDoesNotExistErrorMessage"
             defaultMessage="A field associated with this object no longer exists in the index pattern."
           />
         );
@@ -58,7 +58,7 @@ export const NotFoundErrors = ({ type }: NotFoundErrors) => {
     <EuiCallOut
       title={
         <FormattedMessage
-          id="kbn.management.objects.view.savedObjectProblemErrorMessage"
+          id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
           defaultMessage="There is a problem with this saved object"
         />
       }
@@ -68,7 +68,7 @@ export const NotFoundErrors = ({ type }: NotFoundErrors) => {
       <div>{getMessage()}</div>
       <div>
         <FormattedMessage
-          id="kbn.management.objects.view.howToFixErrorDescription"
+          id="savedObjectsManagement.view.howToFixErrorDescription"
           defaultMessage="If you know what this error means, go ahead and fix it &mdash; otherwise click the delete button above."
         />
       </div>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/index.js b/src/plugins/saved_objects_management/public/management_section/object_view/index.ts
similarity index 93%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/index.js
rename to src/plugins/saved_objects_management/public/management_section/object_view/index.ts
index cdeebdbf7b63a..a823923536d31 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/index.js
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/index.ts
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-export { Flyout } from './flyout';
+export { SavedObjectEdition } from './saved_object_view';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/saved_object_view.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx
similarity index 89%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/saved_object_view.tsx
rename to src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx
index 4984fe3e6d6b8..f714970a5cac3 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/saved_object_view.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx
@@ -26,16 +26,16 @@ import {
   OverlayStart,
   NotificationsStart,
   SimpleSavedObject,
-} from '../../../../../../../core/public';
-import { ISavedObjectsManagementRegistry } from '../../saved_object_registry';
-import { Header, NotFoundErrors, Intro, Form } from './components/object_view';
-import { canViewInApp } from './lib/in_app_url';
-import { SubmittedFormData } from './types';
+} from '../../../../../core/public';
+import { ISavedObjectsManagementServiceRegistry } from '../../services';
+import { Header, NotFoundErrors, Intro, Form } from './components';
+import { canViewInApp } from '../../lib';
+import { SubmittedFormData } from '../types';
 
 interface SavedObjectEditionProps {
   id: string;
   serviceName: string;
-  serviceRegistry: ISavedObjectsManagementRegistry;
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
   capabilities: Capabilities;
   overlays: OverlayStart;
   notifications: NotificationsStart;
@@ -135,17 +135,17 @@ export class SavedObjectEdition extends Component<
     const { type, object } = this.state;
 
     const confirmed = await overlays.openConfirm(
-      i18n.translate('kbn.management.objects.confirmModalOptions.modalDescription', {
+      i18n.translate('savedObjectsManagement.deleteConfirm.modalDescription', {
         defaultMessage: 'This action permanently removes the object from Kibana.',
       }),
       {
         confirmButtonText: i18n.translate(
-          'kbn.management.objects.confirmModalOptions.deleteButtonLabel',
+          'savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel',
           {
             defaultMessage: 'Delete',
           }
         ),
-        title: i18n.translate('kbn.management.objects.confirmModalOptions.modalTitle', {
+        title: i18n.translate('savedObjectsManagement.deleteConfirm.modalTitle', {
           defaultMessage: `Delete '{title}'?`,
           values: {
             title: object?.attributes?.title || 'saved Kibana object',
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
similarity index 73%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap
rename to src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
index 2c0a5d8f6b8f1..fe64df6ff51d1 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
@@ -1,19 +1,19 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`ObjectsTable delete should show a confirm modal 1`] = `
+exports[`SavedObjectsTable delete should show a confirm modal 1`] = `
 <EuiConfirmModal
   buttonColor="danger"
   cancelButtonText={
     <FormattedMessage
       defaultMessage="Cancel"
-      id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
+      id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
       values={Object {}}
     />
   }
   confirmButtonText={
     <FormattedMessage
       defaultMessage="Delete"
-      id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
+      id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
       values={Object {}}
     />
   }
@@ -23,7 +23,7 @@ exports[`ObjectsTable delete should show a confirm modal 1`] = `
   title={
     <FormattedMessage
       defaultMessage="Delete saved objects"
-      id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModalTitle"
+      id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModalTitle"
       values={Object {}}
     />
   }
@@ -31,7 +31,7 @@ exports[`ObjectsTable delete should show a confirm modal 1`] = `
   <p>
     <FormattedMessage
       defaultMessage="This action will delete the following saved objects:"
-      id="kbn.management.objects.deleteSavedObjectsConfirmModalDescription"
+      id="savedObjectsManagement.deleteSavedObjectsConfirmModalDescription"
       values={Object {}}
     />
   </p>
@@ -58,12 +58,10 @@ exports[`ObjectsTable delete should show a confirm modal 1`] = `
       Array [
         Object {
           "id": "1",
-          "title": "Title 1",
           "type": "index-pattern",
         },
         Object {
           "id": "3",
-          "title": "Title 2",
           "type": "dashboard",
         },
       ]
@@ -76,7 +74,7 @@ exports[`ObjectsTable delete should show a confirm modal 1`] = `
 </EuiConfirmModal>
 `;
 
-exports[`ObjectsTable export should allow the user to choose when exporting all 1`] = `
+exports[`SavedObjectsTable export should allow the user to choose when exporting all 1`] = `
 <EuiModal
   onClose={[Function]}
 >
@@ -84,7 +82,7 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
     <EuiModalHeaderTitle>
       <FormattedMessage
         defaultMessage="Export {filteredItemCount, plural, one{# object} other {# objects}}"
-        id="kbn.management.objects.objectsTable.exportObjectsConfirmModalTitle"
+        id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle"
         values={
           Object {
             "filteredItemCount": 4,
@@ -103,7 +101,7 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
       label={
         <FormattedMessage
           defaultMessage="Select which types to export"
-          id="kbn.management.objects.objectsTable.exportObjectsConfirmModalDescription"
+          id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription"
           values={Object {}}
         />
       }
@@ -149,7 +147,7 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
       label={
         <FormattedMessage
           defaultMessage="Include related objects"
-          id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
+          id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
           values={Object {}}
         />
       }
@@ -173,7 +171,7 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
             >
               <FormattedMessage
                 defaultMessage="Cancel"
-                id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
+                id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
                 values={Object {}}
               />
             </EuiButtonEmpty>
@@ -187,7 +185,7 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
             >
               <FormattedMessage
                 defaultMessage="Export all"
-                id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
+                id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
                 values={Object {}}
               />
             </EuiButton>
@@ -199,23 +197,87 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
 </EuiModal>
 `;
 
-exports[`ObjectsTable import should show the flyout 1`] = `
+exports[`SavedObjectsTable import should show the flyout 1`] = `
 <Flyout
+  allowedTypes={
+    Array [
+      "index-pattern",
+      "visualization",
+      "dashboard",
+      "search",
+    ]
+  }
   close={[Function]}
-  confirmModalPromise={[MockFunction]}
   done={[Function]}
+  http={
+    Object {
+      "addLoadingCountSource": [MockFunction],
+      "anonymousPaths": Object {
+        "isAnonymous": [MockFunction],
+        "register": [MockFunction],
+      },
+      "basePath": BasePath {
+        "basePath": "",
+        "get": [Function],
+        "prepend": [Function],
+        "remove": [Function],
+        "serverBasePath": "",
+      },
+      "delete": [MockFunction],
+      "fetch": [MockFunction],
+      "get": [MockFunction],
+      "getLoadingCount$": [MockFunction],
+      "head": [MockFunction],
+      "intercept": [MockFunction],
+      "options": [MockFunction],
+      "patch": [MockFunction],
+      "post": [MockFunction],
+      "put": [MockFunction],
+    }
+  }
   indexPatterns={
     Object {
       "clearCache": [MockFunction],
+      "get": [MockFunction],
+      "make": [Function],
+    }
+  }
+  overlays={
+    Object {
+      "banners": Object {
+        "add": [MockFunction],
+        "get$": [MockFunction],
+        "getComponent": [MockFunction],
+        "remove": [MockFunction],
+        "replace": [MockFunction],
+      },
+      "openConfirm": [MockFunction],
+      "openFlyout": [MockFunction],
+      "openModal": [MockFunction],
+    }
+  }
+  serviceRegistry={
+    Object {
+      "all": [MockFunction],
+      "get": [MockFunction],
+      "register": [MockFunction],
     }
   }
-  newIndexPatternUrl=""
-  services={Array []}
 />
 `;
 
-exports[`ObjectsTable relationships should show the flyout 1`] = `
+exports[`SavedObjectsTable relationships should show the flyout 1`] = `
 <Relationships
+  basePath={
+    BasePath {
+      "basePath": "",
+      "get": [Function],
+      "prepend": [Function],
+      "remove": [Function],
+      "serverBasePath": "",
+    }
+  }
+  canGoInApp={[Function]}
   close={[Function]}
   getRelationships={[Function]}
   goInspectObject={[Function]}
@@ -237,7 +299,7 @@ exports[`ObjectsTable relationships should show the flyout 1`] = `
 />
 `;
 
-exports[`ObjectsTable should render normally 1`] = `
+exports[`SavedObjectsTable should render normally 1`] = `
 <EuiPageContent
   horizontalPosition="center"
 >
@@ -251,7 +313,23 @@ exports[`ObjectsTable should render normally 1`] = `
     size="xs"
   />
   <Table
+    actionRegistry={
+      Object {
+        "getAll": [MockFunction],
+        "has": [MockFunction],
+      }
+    }
+    basePath={
+      BasePath {
+        "basePath": "",
+        "get": [Function],
+        "prepend": [Function],
+        "remove": [Function],
+        "serverBasePath": "",
+      }
+    }
     canDelete={false}
+    canGoInApp={[Function]}
     filterOptions={
       Array [
         Object {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap
similarity index 85%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap
index 34ce8394232ed..4721d166c65e5 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap
@@ -18,7 +18,7 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
       <h2>
         <FormattedMessage
           defaultMessage="Import saved objects"
-          id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
+          id="savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle"
           values={Object {}}
         />
       </h2>
@@ -36,7 +36,7 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
         title={
           <FormattedMessage
             defaultMessage="Index Pattern Conflicts"
-            id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
+            id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle"
             values={Object {}}
           />
         }
@@ -44,7 +44,7 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
         <p>
           <FormattedMessage
             defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
-            id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
+            id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription"
             values={
               Object {
                 "indexPatternLink": <ForwardRef
@@ -52,7 +52,7 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
                 >
                   <FormattedMessage
                     defaultMessage="create a new index pattern"
-                    id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
+                    id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
                     values={Object {}}
                   />
                 </ForwardRef>,
@@ -131,7 +131,7 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
         >
           <FormattedMessage
             defaultMessage="Cancel"
-            id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel"
             values={Object {}}
           />
         </EuiButtonEmpty>
@@ -148,7 +148,7 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
         >
           <FormattedMessage
             defaultMessage="Confirm all changes"
-            id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
             values={Object {}}
           />
         </EuiButton>
@@ -164,6 +164,30 @@ exports[`Flyout conflicts should allow conflict resolution 2`] = `
     Array [
       Object {
         "getConflictResolutions": [Function],
+        "http": Object {
+          "addLoadingCountSource": [MockFunction],
+          "anonymousPaths": Object {
+            "isAnonymous": [MockFunction],
+            "register": [MockFunction],
+          },
+          "basePath": BasePath {
+            "basePath": "",
+            "get": [Function],
+            "prepend": [Function],
+            "remove": [Function],
+            "serverBasePath": "",
+          },
+          "delete": [MockFunction],
+          "fetch": [MockFunction],
+          "get": [MockFunction],
+          "getLoadingCount$": [MockFunction],
+          "head": [MockFunction],
+          "intercept": [MockFunction],
+          "options": [MockFunction],
+          "patch": [MockFunction],
+          "post": [MockFunction],
+          "put": [MockFunction],
+        },
         "state": Object {
           "conflictedIndexPatterns": undefined,
           "conflictedSavedObjectsLinkedToSavedSearches": undefined,
@@ -243,7 +267,7 @@ exports[`Flyout conflicts should handle errors 1`] = `
   title={
     <FormattedMessage
       defaultMessage="Import failed"
-      id="kbn.management.objects.objectsTable.flyout.importFailedTitle"
+      id="savedObjectsManagement.objectsTable.flyout.importFailedTitle"
       values={Object {}}
     />
   }
@@ -251,7 +275,7 @@ exports[`Flyout conflicts should handle errors 1`] = `
   <p>
     <FormattedMessage
       defaultMessage="Failed to import {failedImportCount} of {totalImportCount} objects. Import failed"
-      id="kbn.management.objects.objectsTable.flyout.importFailedDescription"
+      id="savedObjectsManagement.objectsTable.flyout.importFailedDescription"
       values={
         Object {
           "failedImportCount": 1,
@@ -272,7 +296,7 @@ exports[`Flyout errors should display unsupported type errors properly 1`] = `
   title={
     <FormattedMessage
       defaultMessage="Import failed"
-      id="kbn.management.objects.objectsTable.flyout.importFailedTitle"
+      id="savedObjectsManagement.objectsTable.flyout.importFailedTitle"
       values={Object {}}
     />
   }
@@ -280,7 +304,7 @@ exports[`Flyout errors should display unsupported type errors properly 1`] = `
   <p>
     <FormattedMessage
       defaultMessage="Failed to import {failedImportCount} of {totalImportCount} objects. Import failed"
-      id="kbn.management.objects.objectsTable.flyout.importFailedDescription"
+      id="savedObjectsManagement.objectsTable.flyout.importFailedDescription"
       values={
         Object {
           "failedImportCount": 1,
@@ -313,7 +337,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
       <h2>
         <FormattedMessage
           defaultMessage="Import saved objects"
-          id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
+          id="savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle"
           values={Object {}}
         />
       </h2>
@@ -331,7 +355,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
         title={
           <FormattedMessage
             defaultMessage="Support for JSON files is going away"
-            id="kbn.management.objects.objectsTable.flyout.legacyFileUsedTitle"
+            id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle"
             values={Object {}}
           />
         }
@@ -339,7 +363,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
         <p>
           <FormattedMessage
             defaultMessage="Use our updated export to generate NDJSON files, and you'll be all set."
-            id="kbn.management.objects.objectsTable.flyout.legacyFileUsedBody"
+            id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody"
             values={Object {}}
           />
         </p>
@@ -356,7 +380,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
         title={
           <FormattedMessage
             defaultMessage="Index Pattern Conflicts"
-            id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
+            id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle"
             values={Object {}}
           />
         }
@@ -364,7 +388,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
         <p>
           <FormattedMessage
             defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
-            id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
+            id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription"
             values={
               Object {
                 "indexPatternLink": <ForwardRef
@@ -372,7 +396,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
                 >
                   <FormattedMessage
                     defaultMessage="create a new index pattern"
-                    id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
+                    id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
                     values={Object {}}
                   />
                 </ForwardRef>,
@@ -462,7 +486,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
         >
           <FormattedMessage
             defaultMessage="Cancel"
-            id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel"
             values={Object {}}
           />
         </EuiButtonEmpty>
@@ -479,7 +503,7 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
         >
           <FormattedMessage
             defaultMessage="Confirm all changes"
-            id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
             values={Object {}}
           />
         </EuiButton>
@@ -498,7 +522,7 @@ Array [
     title={
       <FormattedMessage
         defaultMessage="Support for JSON files is going away"
-        id="kbn.management.objects.objectsTable.flyout.legacyFileUsedTitle"
+        id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle"
         values={Object {}}
       />
     }
@@ -506,7 +530,7 @@ Array [
     <p>
       <FormattedMessage
         defaultMessage="Use our updated export to generate NDJSON files, and you'll be all set."
-        id="kbn.management.objects.objectsTable.flyout.legacyFileUsedBody"
+        id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody"
         values={Object {}}
       />
     </p>
@@ -518,7 +542,7 @@ Array [
     title={
       <FormattedMessage
         defaultMessage="Index Pattern Conflicts"
-        id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
+        id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle"
         values={Object {}}
       />
     }
@@ -526,7 +550,7 @@ Array [
     <p>
       <FormattedMessage
         defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
-        id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
+        id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription"
         values={
           Object {
             "indexPatternLink": <ForwardRef
@@ -534,7 +558,7 @@ Array [
             >
               <FormattedMessage
                 defaultMessage="create a new index pattern"
-                id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
+                id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
                 values={Object {}}
               />
             </ForwardRef>,
@@ -548,7 +572,7 @@ Array [
     title={
       <FormattedMessage
         defaultMessage="Sorry, there was an error"
-        id="kbn.management.objects.objectsTable.flyout.errorCalloutTitle"
+        id="savedObjectsManagement.objectsTable.flyout.errorCalloutTitle"
         values={Object {}}
       />
     }
@@ -578,7 +602,7 @@ exports[`Flyout should render import step 1`] = `
       <h2>
         <FormattedMessage
           defaultMessage="Import saved objects"
-          id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
+          id="savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle"
           values={Object {}}
         />
       </h2>
@@ -595,7 +619,7 @@ exports[`Flyout should render import step 1`] = `
         label={
           <FormattedMessage
             defaultMessage="Please select a file to import"
-            id="kbn.management.objects.objectsTable.flyout.selectFileToImportFormRowLabel"
+            id="savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel"
             values={Object {}}
           />
         }
@@ -607,7 +631,7 @@ exports[`Flyout should render import step 1`] = `
           initialPromptText={
             <FormattedMessage
               defaultMessage="Import"
-              id="kbn.management.objects.objectsTable.flyout.importPromptText"
+              id="savedObjectsManagement.objectsTable.flyout.importPromptText"
               values={Object {}}
             />
           }
@@ -628,7 +652,7 @@ exports[`Flyout should render import step 1`] = `
           label={
             <FormattedMessage
               defaultMessage="Automatically overwrite all saved objects?"
-              id="kbn.management.objects.objectsTable.flyout.overwriteSavedObjectsLabel"
+              id="savedObjectsManagement.objectsTable.flyout.overwriteSavedObjectsLabel"
               values={Object {}}
             />
           }
@@ -651,7 +675,7 @@ exports[`Flyout should render import step 1`] = `
         >
           <FormattedMessage
             defaultMessage="Cancel"
-            id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel"
             values={Object {}}
           />
         </EuiButtonEmpty>
@@ -668,7 +692,7 @@ exports[`Flyout should render import step 1`] = `
         >
           <FormattedMessage
             defaultMessage="Import"
-            id="kbn.management.objects.objectsTable.flyout.import.confirmButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel"
             values={Object {}}
           />
         </EuiButton>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/__snapshots__/header.test.js.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap
similarity index 88%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/__snapshots__/header.test.js.snap
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap
index 51bd51a5e2e58..642a5030e4ec0 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/__snapshots__/header.test.js.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap
@@ -13,7 +13,7 @@ exports[`Header should render normally 1`] = `
         <h1>
           <FormattedMessage
             defaultMessage="Saved Objects"
-            id="kbn.management.objects.objectsTable.header.savedObjectsTitle"
+            id="savedObjectsManagement.objectsTable.header.savedObjectsTitle"
             values={Object {}}
           />
         </h1>
@@ -38,7 +38,7 @@ exports[`Header should render normally 1`] = `
           >
             <FormattedMessage
               defaultMessage="Export {filteredCount, plural, one{# object} other {# objects}}"
-              id="kbn.management.objects.objectsTable.header.exportButtonLabel"
+              id="savedObjectsManagement.objectsTable.header.exportButtonLabel"
               values={
                 Object {
                   "filteredCount": 2,
@@ -58,7 +58,7 @@ exports[`Header should render normally 1`] = `
           >
             <FormattedMessage
               defaultMessage="Import"
-              id="kbn.management.objects.objectsTable.header.importButtonLabel"
+              id="savedObjectsManagement.objectsTable.header.importButtonLabel"
               values={Object {}}
             />
           </EuiButtonEmpty>
@@ -73,7 +73,7 @@ exports[`Header should render normally 1`] = `
           >
             <FormattedMessage
               defaultMessage="Refresh"
-              id="kbn.management.objects.objectsTable.header.refreshButtonLabel"
+              id="savedObjectsManagement.objectsTable.header.refreshButtonLabel"
               values={Object {}}
             />
           </EuiButtonEmpty>
@@ -93,7 +93,7 @@ exports[`Header should render normally 1`] = `
       >
         <FormattedMessage
           defaultMessage="From here you can delete saved objects, such as saved searches. You can also edit the raw data of saved objects. Typically objects are only modified via their associated application, which is probably what you should use instead of this screen."
-          id="kbn.management.objects.objectsTable.howToDeleteSavedObjectsDescription"
+          id="savedObjectsManagement.objectsTable.howToDeleteSavedObjectsDescription"
           values={Object {}}
         />
       </EuiTextColor>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap
similarity index 99%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap
index 728944f3ccbfe..a8bb691cd54e9 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap
@@ -202,7 +202,7 @@ exports[`Relationships should render errors 1`] = `
       title={
         <FormattedMessage
           defaultMessage="Error"
-          id="kbn.management.objects.objectsTable.relationships.renderErrorMessage"
+          id="savedObjectsManagement.objectsTable.relationships.renderErrorMessage"
           values={Object {}}
         />
       }
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap
similarity index 93%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap
index a4dcfb9c38184..d09dd6f8b868b 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap
@@ -36,7 +36,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
         >
           <FormattedMessage
             defaultMessage="Delete"
-            id="kbn.management.objects.objectsTable.table.deleteButtonLabel"
+            id="savedObjectsManagement.objectsTable.table.deleteButtonLabel"
             values={Object {}}
           />
         </EuiButton>,
@@ -51,7 +51,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
             >
               <FormattedMessage
                 defaultMessage="Export"
-                id="kbn.management.objects.objectsTable.table.exportPopoverButtonLabel"
+                id="savedObjectsManagement.objectsTable.table.exportPopoverButtonLabel"
                 values={Object {}}
               />
             </EuiButton>
@@ -72,7 +72,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
             label={
               <FormattedMessage
                 defaultMessage="Options"
-                id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportOptionsLabel"
+                id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportOptionsLabel"
                 values={Object {}}
               />
             }
@@ -83,7 +83,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
               label={
                 <FormattedMessage
                   defaultMessage="Include related objects"
-                  id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
+                  id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
                   values={Object {}}
                 />
               }
@@ -106,7 +106,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
             >
               <FormattedMessage
                 defaultMessage="Export"
-                id="kbn.management.objects.objectsTable.table.exportButtonLabel"
+                id="savedObjectsManagement.objectsTable.table.exportButtonLabel"
                 values={Object {}}
               />
             </EuiButton>
@@ -171,6 +171,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
       items={
         Array [
           Object {
+            "attributes": Object {},
             "id": "1",
             "meta": Object {
               "editUrl": "#/management/kibana/index_patterns/1",
@@ -181,6 +182,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
               },
               "title": "MyIndexPattern*",
             },
+            "references": Array [],
             "type": "index-pattern",
           },
         ]
@@ -249,7 +251,7 @@ exports[`Table should render normally 1`] = `
         >
           <FormattedMessage
             defaultMessage="Delete"
-            id="kbn.management.objects.objectsTable.table.deleteButtonLabel"
+            id="savedObjectsManagement.objectsTable.table.deleteButtonLabel"
             values={Object {}}
           />
         </EuiButton>,
@@ -264,7 +266,7 @@ exports[`Table should render normally 1`] = `
             >
               <FormattedMessage
                 defaultMessage="Export"
-                id="kbn.management.objects.objectsTable.table.exportPopoverButtonLabel"
+                id="savedObjectsManagement.objectsTable.table.exportPopoverButtonLabel"
                 values={Object {}}
               />
             </EuiButton>
@@ -285,7 +287,7 @@ exports[`Table should render normally 1`] = `
             label={
               <FormattedMessage
                 defaultMessage="Options"
-                id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportOptionsLabel"
+                id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportOptionsLabel"
                 values={Object {}}
               />
             }
@@ -296,7 +298,7 @@ exports[`Table should render normally 1`] = `
               label={
                 <FormattedMessage
                   defaultMessage="Include related objects"
-                  id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
+                  id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
                   values={Object {}}
                 />
               }
@@ -319,7 +321,7 @@ exports[`Table should render normally 1`] = `
             >
               <FormattedMessage
                 defaultMessage="Export"
-                id="kbn.management.objects.objectsTable.table.exportButtonLabel"
+                id="savedObjectsManagement.objectsTable.table.exportButtonLabel"
                 values={Object {}}
               />
             </EuiButton>
@@ -384,6 +386,7 @@ exports[`Table should render normally 1`] = `
       items={
         Array [
           Object {
+            "attributes": Object {},
             "id": "1",
             "meta": Object {
               "editUrl": "#/management/kibana/index_patterns/1",
@@ -394,6 +397,7 @@ exports[`Table should render normally 1`] = `
               },
               "title": "MyIndexPattern*",
             },
+            "references": Array [],
             "type": "index-pattern",
           },
         ]
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.mocks.ts b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.mocks.ts
new file mode 100644
index 0000000000000..b5361d212954f
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.mocks.ts
@@ -0,0 +1,44 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const importFileMock = jest.fn();
+jest.doMock('../../../lib/import_file', () => ({
+  importFile: importFileMock,
+}));
+
+export const resolveImportErrorsMock = jest.fn();
+jest.doMock('../../../lib/resolve_import_errors', () => ({
+  resolveImportErrors: resolveImportErrorsMock,
+}));
+
+export const importLegacyFileMock = jest.fn();
+jest.doMock('../../../lib/import_legacy_file', () => ({
+  importLegacyFile: importLegacyFileMock,
+}));
+
+export const resolveSavedObjectsMock = jest.fn();
+export const resolveSavedSearchesMock = jest.fn();
+export const resolveIndexPatternConflictsMock = jest.fn();
+export const saveObjectsMock = jest.fn();
+jest.doMock('../../../lib/resolve_saved_objects', () => ({
+  resolveSavedObjects: resolveSavedObjectsMock,
+  resolveSavedSearches: resolveSavedSearchesMock,
+  resolveIndexPatternConflicts: resolveIndexPatternConflictsMock,
+  saveObjects: saveObjectsMock,
+}));
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx
similarity index 75%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx
index 0d16e0ae35dd6..5d713ff044f24 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx
@@ -17,68 +17,62 @@
  * under the License.
  */
 
+import {
+  importFileMock,
+  importLegacyFileMock,
+  resolveImportErrorsMock,
+  resolveIndexPatternConflictsMock,
+  resolveSavedObjectsMock,
+  resolveSavedSearchesMock,
+  saveObjectsMock,
+} from './flyout.test.mocks';
+
 import React from 'react';
 import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
-import { mockManagementPlugin } from '../../../../../../../../../../../../plugins/index_pattern_management/public/mocks';
-import { Flyout } from '../flyout';
-
-jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
-
-jest.mock('../../../../../lib/import_file', () => ({
-  importFile: jest.fn(),
-}));
-
-jest.mock('../../../../../lib/resolve_import_errors', () => ({
-  resolveImportErrors: jest.fn(),
-}));
-
-jest.mock('ui/chrome', () => ({
-  addBasePath: () => {},
-  getInjected: () => ['index-pattern', 'visualization', 'dashboard', 'search'],
-}));
-
-jest.mock('../../../../../lib/import_legacy_file', () => ({
-  importLegacyFile: jest.fn(),
-}));
-
-jest.mock('../../../../../lib/resolve_saved_objects', () => ({
-  resolveSavedObjects: jest.fn(),
-  resolveSavedSearches: jest.fn(),
-  resolveIndexPatternConflicts: jest.fn(),
-  saveObjects: jest.fn(),
-}));
-
-jest.mock('../../../../../../../../../../../../plugins/index_pattern_management/public', () => ({
-  setup: mockManagementPlugin.createSetupContract(),
-  start: mockManagementPlugin.createStartContract(),
-}));
-
-jest.mock('ui/notify', () => ({}));
-
-const defaultProps = {
-  close: jest.fn(),
-  done: jest.fn(),
-  services: [],
-  newIndexPatternUrl: '',
-  getConflictResolutions: jest.fn(),
-  confirmModalPromise: jest.fn(),
-  indexPatterns: {
-    getFields: jest.fn().mockImplementation(() => [{ id: '1' }, { id: '2' }]),
-  },
-};
-
-const mockFile = {
+import { coreMock } from '../../../../../../core/public/mocks';
+import { serviceRegistryMock } from '../../../services/service_registry.mock';
+import { Flyout, FlyoutProps, FlyoutState } from './flyout';
+import { ShallowWrapper } from 'enzyme';
+
+const mockFile = ({
   name: 'foo.ndjson',
   path: '/home/foo.ndjson',
-};
-const legacyMockFile = {
+} as unknown) as File;
+const legacyMockFile = ({
   name: 'foo.json',
   path: '/home/foo.json',
-};
+} as unknown) as File;
 
 describe('Flyout', () => {
+  let defaultProps: FlyoutProps;
+
+  const shallowRender = (props: FlyoutProps) => {
+    return (shallowWithI18nProvider(<Flyout {...props} />) as unknown) as ShallowWrapper<
+      FlyoutProps,
+      FlyoutState,
+      Flyout
+    >;
+  };
+
+  beforeEach(() => {
+    const { http, overlays } = coreMock.createStart();
+
+    defaultProps = {
+      close: jest.fn(),
+      done: jest.fn(),
+      newIndexPatternUrl: '',
+      indexPatterns: {
+        getFields: jest.fn().mockImplementation(() => [{ id: '1' }, { id: '2' }]),
+      } as any,
+      overlays,
+      http,
+      allowedTypes: ['search', 'index-pattern', 'visualization'],
+      serviceRegistry: serviceRegistryMock.create(),
+    };
+  });
+
   it('should render import step', async () => {
-    const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+    const component = shallowRender(defaultProps);
 
     // Ensure all promises resolve
     await new Promise(resolve => process.nextTick(resolve));
@@ -89,7 +83,7 @@ describe('Flyout', () => {
   });
 
   it('should toggle the overwrite all control', async () => {
-    const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+    const component = shallowRender(defaultProps);
 
     // Ensure all promises resolve
     await new Promise(resolve => process.nextTick(resolve));
@@ -102,7 +96,7 @@ describe('Flyout', () => {
   });
 
   it('should allow picking a file', async () => {
-    const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+    const component = shallowRender(defaultProps);
 
     // Ensure all promises resolve
     await new Promise(resolve => process.nextTick(resolve));
@@ -115,7 +109,7 @@ describe('Flyout', () => {
   });
 
   it('should allow removing a file', async () => {
-    const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+    const component = shallowRender(defaultProps);
 
     // Ensure all promises resolve
     await Promise.resolve();
@@ -130,22 +124,21 @@ describe('Flyout', () => {
   });
 
   it('should handle invalid files', async () => {
-    const { importLegacyFile } = require('../../../../../lib/import_legacy_file');
-    const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+    const component = shallowRender(defaultProps);
 
     // Ensure all promises resolve
     await new Promise(resolve => process.nextTick(resolve));
     // Ensure the state changes are reflected
     component.update();
 
-    importLegacyFile.mockImplementation(() => {
+    importLegacyFileMock.mockImplementation(() => {
       throw new Error('foobar');
     });
 
     await component.instance().legacyImport();
     expect(component.state('error')).toBe('The file could not be processed.');
 
-    importLegacyFile.mockImplementation(() => ({
+    importLegacyFileMock.mockImplementation(() => ({
       invalid: true,
     }));
 
@@ -156,11 +149,8 @@ describe('Flyout', () => {
   });
 
   describe('conflicts', () => {
-    const { importFile } = require('../../../../../lib/import_file');
-    const { resolveImportErrors } = require('../../../../../lib/resolve_import_errors');
-
     beforeEach(() => {
-      importFile.mockImplementation(() => ({
+      importFileMock.mockImplementation(() => ({
         success: false,
         successCount: 0,
         errors: [
@@ -180,7 +170,7 @@ describe('Flyout', () => {
           },
         ],
       }));
-      resolveImportErrors.mockImplementation(() => ({
+      resolveImportErrorsMock.mockImplementation(() => ({
         status: 'success',
         importCount: 1,
         failedImports: [],
@@ -188,7 +178,7 @@ describe('Flyout', () => {
     });
 
     it('should figure out unmatchedReferences', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -198,7 +188,7 @@ describe('Flyout', () => {
       component.setState({ file: mockFile, isLegacyFile: false });
       await component.instance().import();
 
-      expect(importFile).toHaveBeenCalledWith(mockFile, true);
+      expect(importFileMock).toHaveBeenCalledWith(defaultProps.http, mockFile, true);
       expect(component.state()).toMatchObject({
         conflictedIndexPatterns: undefined,
         conflictedSavedObjectsLinkedToSavedSearches: undefined,
@@ -223,7 +213,7 @@ describe('Flyout', () => {
     });
 
     it('should allow conflict resolution', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -239,7 +229,7 @@ describe('Flyout', () => {
 
       // Ensure we can change the resolution
       component.instance().onIndexChanged('MyIndexPattern*', { target: { value: '2' } });
-      expect(component.state('unmatchedReferences')[0].newIndexPatternId).toBe('2');
+      expect(component.state('unmatchedReferences')![0].newIndexPatternId).toBe('2');
 
       // Let's resolve now
       await component
@@ -247,18 +237,18 @@ describe('Flyout', () => {
         .simulate('click');
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
-      expect(resolveImportErrors).toMatchSnapshot();
+      expect(resolveImportErrorsMock).toMatchSnapshot();
     });
 
     it('should handle errors', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
       // Ensure the state changes are reflected
       component.update();
 
-      resolveImportErrors.mockImplementation(() => ({
+      resolveImportErrorsMock.mockImplementation(() => ({
         status: 'success',
         importCount: 0,
         failedImports: [
@@ -303,18 +293,15 @@ describe('Flyout', () => {
   });
 
   describe('errors', () => {
-    const { importFile } = require('../../../../../lib/import_file');
-    const { resolveImportErrors } = require('../../../../../lib/resolve_import_errors');
-
     it('should display unsupported type errors properly', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await Promise.resolve();
       // Ensure the state changes are reflected
       component.update();
 
-      importFile.mockImplementation(() => ({
+      importFileMock.mockImplementation(() => ({
         success: false,
         successCount: 0,
         errors: [
@@ -328,7 +315,7 @@ describe('Flyout', () => {
           },
         ],
       }));
-      resolveImportErrors.mockImplementation(() => ({
+      resolveImportErrorsMock.mockImplementation(() => ({
         status: 'success',
         importCount: 0,
         failedImports: [
@@ -372,14 +359,6 @@ describe('Flyout', () => {
   });
 
   describe('legacy conflicts', () => {
-    const { importLegacyFile } = require('../../../../../lib/import_legacy_file');
-    const {
-      resolveSavedObjects,
-      resolveSavedSearches,
-      resolveIndexPatternConflicts,
-      saveObjects,
-    } = require('../../../../../lib/resolve_saved_objects');
-
     const mockData = [
       {
         _id: '1',
@@ -406,7 +385,7 @@ describe('Flyout', () => {
         },
         obj: {
           searchSource: {
-            getOwnField: field => {
+            getOwnField: (field: string) => {
               if (field === 'index') {
                 return 'MyIndexPattern*';
               }
@@ -426,8 +405,8 @@ describe('Flyout', () => {
     const mockConflictedSearchDocs = [3];
 
     beforeEach(() => {
-      importLegacyFile.mockImplementation(() => mockData);
-      resolveSavedObjects.mockImplementation(() => ({
+      importLegacyFileMock.mockImplementation(() => mockData);
+      resolveSavedObjectsMock.mockImplementation(() => ({
         conflictedIndexPatterns: mockConflictedIndexPatterns,
         conflictedSavedObjectsLinkedToSavedSearches: mockConflictedSavedObjectsLinkedToSavedSearches,
         conflictedSearchDocs: mockConflictedSearchDocs,
@@ -437,7 +416,7 @@ describe('Flyout', () => {
     });
 
     it('should figure out unmatchedReferences', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -447,14 +426,14 @@ describe('Flyout', () => {
       component.setState({ file: legacyMockFile, isLegacyFile: true });
       await component.instance().legacyImport();
 
-      expect(importLegacyFile).toHaveBeenCalledWith(legacyMockFile);
+      expect(importLegacyFileMock).toHaveBeenCalledWith(legacyMockFile);
       // Remove the last element from data since it should be filtered out
-      expect(resolveSavedObjects).toHaveBeenCalledWith(
+      expect(resolveSavedObjectsMock).toHaveBeenCalledWith(
         mockData.slice(0, 2).map(doc => ({ ...doc, _migrationVersion: {} })),
         true,
-        defaultProps.services,
+        defaultProps.serviceRegistry.all().map(s => s.service),
         defaultProps.indexPatterns,
-        defaultProps.confirmModalPromise
+        defaultProps.overlays.openConfirm
       );
 
       expect(component.state()).toMatchObject({
@@ -492,7 +471,7 @@ describe('Flyout', () => {
     });
 
     it('should allow conflict resolution', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -508,7 +487,7 @@ describe('Flyout', () => {
 
       // Ensure we can change the resolution
       component.instance().onIndexChanged('MyIndexPattern*', { target: { value: '2' } });
-      expect(component.state('unmatchedReferences')[0].newIndexPatternId).toBe('2');
+      expect(component.state('unmatchedReferences')![0].newIndexPatternId).toBe('2');
 
       // Let's resolve now
       await component
@@ -516,33 +495,33 @@ describe('Flyout', () => {
         .simulate('click');
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
-      expect(resolveIndexPatternConflicts).toHaveBeenCalledWith(
+      expect(resolveIndexPatternConflictsMock).toHaveBeenCalledWith(
         component.instance().resolutions,
         mockConflictedIndexPatterns,
         true,
         defaultProps.indexPatterns
       );
-      expect(saveObjects).toHaveBeenCalledWith(
+      expect(saveObjectsMock).toHaveBeenCalledWith(
         mockConflictedSavedObjectsLinkedToSavedSearches,
         true
       );
-      expect(resolveSavedSearches).toHaveBeenCalledWith(
+      expect(resolveSavedSearchesMock).toHaveBeenCalledWith(
         mockConflictedSearchDocs,
-        defaultProps.services,
+        defaultProps.serviceRegistry.all().map(s => s.service),
         defaultProps.indexPatterns,
         true
       );
     });
 
     it('should handle errors', async () => {
-      const component = shallowWithI18nProvider(<Flyout {...defaultProps} />);
+      const component = shallowRender(defaultProps);
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
       // Ensure the state changes are reflected
       component.update();
 
-      resolveIndexPatternConflicts.mockImplementation(() => {
+      resolveIndexPatternConflictsMock.mockImplementation(() => {
         throw new Error('foobar');
       });
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx
similarity index 77%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx
index da2221bb54203..45788dcb601ae 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx
@@ -18,7 +18,6 @@
  */
 
 import React, { Component, Fragment } from 'react';
-import PropTypes from 'prop-types';
 import { take, get as getField } from 'lodash';
 import {
   EuiFlyout,
@@ -32,6 +31,7 @@ import {
   EuiForm,
   EuiFormRow,
   EuiSwitch,
+  // @ts-ignore
   EuiFilePicker,
   EuiInMemoryTable,
   EuiSelect,
@@ -47,34 +47,62 @@ import {
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-
+import { OverlayStart, HttpStart } from 'src/core/public';
+import { IndexPatternsContract, IIndexPattern } from '../../../../../data/public';
 import {
   importFile,
   importLegacyFile,
   resolveImportErrors,
   logLegacyImport,
   getDefaultTitle,
-} from '../../../../lib';
-import { processImportResponse } from '../../../../lib/process_import_response';
+  processImportResponse,
+  ProcessedImportResponse,
+} from '../../../lib';
 import {
   resolveSavedObjects,
   resolveSavedSearches,
   resolveIndexPatternConflicts,
   saveObjects,
-} from '../../../../lib/resolve_saved_objects';
-import { POSSIBLE_TYPES } from '../../objects_table';
-
-export class Flyout extends Component {
-  static propTypes = {
-    close: PropTypes.func.isRequired,
-    done: PropTypes.func.isRequired,
-    services: PropTypes.array.isRequired,
-    newIndexPatternUrl: PropTypes.string.isRequired,
-    indexPatterns: PropTypes.object.isRequired,
-    confirmModalPromise: PropTypes.func.isRequired,
-  };
+} from '../../../lib/resolve_saved_objects';
+import { ISavedObjectsManagementServiceRegistry } from '../../../services';
+
+export interface FlyoutProps {
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
+  allowedTypes: string[];
+  close: () => void;
+  done: () => void;
+  newIndexPatternUrl: string;
+  indexPatterns: IndexPatternsContract;
+  overlays: OverlayStart;
+  http: HttpStart;
+}
+
+export interface FlyoutState {
+  conflictedIndexPatterns?: any[];
+  conflictedSavedObjectsLinkedToSavedSearches?: any[];
+  conflictedSearchDocs?: any[];
+  unmatchedReferences?: ProcessedImportResponse['unmatchedReferences'];
+  failedImports?: ProcessedImportResponse['failedImports'];
+  conflictingRecord?: ConflictingRecord;
+  error?: string;
+  file?: File;
+  importCount: number;
+  indexPatterns?: IIndexPattern[];
+  isOverwriteAllChecked: boolean;
+  loadingMessage?: string;
+  isLegacyFile: boolean;
+  status: string;
+}
+
+interface ConflictingRecord {
+  id: string;
+  type: string;
+  title: string;
+  done: (success: boolean) => void;
+}
 
-  constructor(props) {
+export class Flyout extends Component<FlyoutProps, FlyoutState> {
+  constructor(props: FlyoutProps) {
     super(props);
 
     this.state = {
@@ -100,7 +128,7 @@ export class Flyout extends Component {
 
   fetchIndexPatterns = async () => {
     const indexPatterns = await this.props.indexPatterns.getFields(['id', 'title']);
-    this.setState({ indexPatterns });
+    this.setState({ indexPatterns } as any);
   };
 
   changeOverwriteAll = () => {
@@ -109,11 +137,12 @@ export class Flyout extends Component {
     }));
   };
 
-  setImportFile = ([file]) => {
-    if (!file) {
+  setImportFile = (files: FileList | null) => {
+    if (!files || !files[0]) {
       this.setState({ file: undefined, isLegacyFile: false });
       return;
     }
+    const file = files[0];
     this.setState({
       file,
       isLegacyFile: /\.json$/i.test(file.name) || file.type === 'application/json',
@@ -126,30 +155,29 @@ export class Flyout extends Component {
    * Does the initial import of a file, resolveImportErrors then handles errors and retries
    */
   import = async () => {
+    const { http } = this.props;
     const { file, isOverwriteAllChecked } = this.state;
     this.setState({ status: 'loading', error: undefined });
 
     // Import the file
-    let response;
     try {
-      response = await importFile(file, isOverwriteAllChecked);
+      const response = await importFile(http, file!, isOverwriteAllChecked);
+      this.setState(processImportResponse(response), () => {
+        // Resolve import errors right away if there's no index patterns to match
+        // This will ask about overwriting each object, etc
+        if (this.state.unmatchedReferences?.length === 0) {
+          this.resolveImportErrors();
+        }
+      });
     } catch (e) {
       this.setState({
         status: 'error',
-        error: i18n.translate('kbn.management.objects.objectsTable.flyout.importFileErrorMessage', {
+        error: i18n.translate('savedObjectsManagement.objectsTable.flyout.importFileErrorMessage', {
           defaultMessage: 'The file could not be processed.',
         }),
       });
       return;
     }
-
-    this.setState(processImportResponse(response), () => {
-      // Resolve import errors right away if there's no index patterns to match
-      // This will ask about overwriting each object, etc
-      if (this.state.unmatchedReferences.length === 0) {
-        this.resolveImportErrors();
-      }
-    });
   };
 
   /**
@@ -160,10 +188,10 @@ export class Flyout extends Component {
    * @param {array} objects List of objects to request the user if they wish to overwrite it
    * @return {Promise<array>} An object with the key being "type:id" and value the resolution chosen by the user
    */
-  getConflictResolutions = async objects => {
-    const resolutions = {};
+  getConflictResolutions = async (objects: any[]) => {
+    const resolutions: Record<string, boolean> = {};
     for (const { type, id, title } of objects) {
-      const overwrite = await new Promise(resolve => {
+      const overwrite = await new Promise<boolean>(resolve => {
         this.setState({
           conflictingRecord: {
             id,
@@ -193,6 +221,7 @@ export class Flyout extends Component {
 
     try {
       const updatedState = await resolveImportErrors({
+        http: this.props.http,
         state: this.state,
         getConflictResolutions: this.getConflictResolutions,
       });
@@ -201,7 +230,7 @@ export class Flyout extends Component {
       this.setState({
         status: 'error',
         error: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.resolveImportErrorsFileErrorMessage',
+          'savedObjectsManagement.objectsTable.flyout.resolveImportErrorsFileErrorMessage',
           { defaultMessage: 'The file could not be processed.' }
         ),
       });
@@ -209,22 +238,22 @@ export class Flyout extends Component {
   };
 
   legacyImport = async () => {
-    const { services, indexPatterns, confirmModalPromise } = this.props;
+    const { serviceRegistry, indexPatterns, overlays, http, allowedTypes } = this.props;
     const { file, isOverwriteAllChecked } = this.state;
 
     this.setState({ status: 'loading', error: undefined });
 
     // Log warning on server, don't wait for response
-    logLegacyImport();
+    logLegacyImport(http);
 
     let contents;
     try {
-      contents = await importLegacyFile(file);
+      contents = await importLegacyFile(file!);
     } catch (e) {
       this.setState({
         status: 'error',
         error: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.importLegacyFileErrorMessage',
+          'savedObjectsManagement.objectsTable.flyout.importLegacyFileErrorMessage',
           { defaultMessage: 'The file could not be processed.' }
         ),
       });
@@ -235,7 +264,7 @@ export class Flyout extends Component {
       this.setState({
         status: 'error',
         error: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage',
+          'savedObjectsManagement.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage',
           { defaultMessage: 'Saved objects file format is invalid and cannot be imported.' }
         ),
       });
@@ -243,7 +272,7 @@ export class Flyout extends Component {
     }
 
     contents = contents
-      .filter(content => POSSIBLE_TYPES.includes(content._type))
+      .filter(content => allowedTypes.includes(content._type))
       .map(doc => ({
         ...doc,
         // The server assumes that documents with no migrationVersion are up to date.
@@ -263,18 +292,18 @@ export class Flyout extends Component {
     } = await resolveSavedObjects(
       contents,
       isOverwriteAllChecked,
-      services,
+      serviceRegistry.all().map(e => e.service),
       indexPatterns,
-      confirmModalPromise
+      overlays.openConfirm
     );
 
-    const byId = {};
+    const byId: Record<string, any[]> = {};
     conflictedIndexPatterns
       .map(({ doc, obj }) => {
         return { doc, obj: obj._serialize() };
       })
       .forEach(({ doc, obj }) =>
-        obj.references.forEach(ref => {
+        obj.references.forEach((ref: Record<string, any>) => {
           byId[ref.id] = byId[ref.id] != null ? byId[ref.id].concat({ doc, obj }) : [{ doc, obj }];
         })
       );
@@ -291,7 +320,7 @@ export class Flyout extends Component {
         });
         return accum;
       },
-      []
+      [] as any[]
     );
 
     this.setState({
@@ -305,12 +334,12 @@ export class Flyout extends Component {
     });
   };
 
-  get hasUnmatchedReferences() {
+  public get hasUnmatchedReferences() {
     return this.state.unmatchedReferences && this.state.unmatchedReferences.length > 0;
   }
 
-  get resolutions() {
-    return this.state.unmatchedReferences.reduce(
+  public get resolutions() {
+    return this.state.unmatchedReferences!.reduce(
       (accum, { existingIndexPatternId, newIndexPatternId }) => {
         if (newIndexPatternId) {
           accum.push({
@@ -320,7 +349,7 @@ export class Flyout extends Component {
         }
         return accum;
       },
-      []
+      [] as Array<{ oldId: string; newId: string }>
     );
   }
 
@@ -333,7 +362,7 @@ export class Flyout extends Component {
       failedImports,
     } = this.state;
 
-    const { services, indexPatterns } = this.props;
+    const { serviceRegistry, indexPatterns } = this.props;
 
     this.setState({
       error: undefined,
@@ -350,48 +379,48 @@ export class Flyout extends Component {
         // Do not Promise.all these calls as the order matters
         this.setState({
           loadingMessage: i18n.translate(
-            'kbn.management.objects.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage',
+            'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage',
             { defaultMessage: 'Resolving conflicts…' }
           ),
         });
         if (resolutions.length) {
           importCount += await resolveIndexPatternConflicts(
             resolutions,
-            conflictedIndexPatterns,
+            conflictedIndexPatterns!,
             isOverwriteAllChecked,
-            this.props.indexPatterns
+            indexPatterns
           );
         }
         this.setState({
           loadingMessage: i18n.translate(
-            'kbn.management.objects.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage',
+            'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage',
             { defaultMessage: 'Saving conflicts…' }
           ),
         });
         importCount += await saveObjects(
-          conflictedSavedObjectsLinkedToSavedSearches,
+          conflictedSavedObjectsLinkedToSavedSearches!,
           isOverwriteAllChecked
         );
         this.setState({
           loadingMessage: i18n.translate(
-            'kbn.management.objects.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage',
+            'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage',
             { defaultMessage: 'Ensure saved searches are linked properly…' }
           ),
         });
         importCount += await resolveSavedSearches(
-          conflictedSearchDocs,
-          services,
+          conflictedSearchDocs!,
+          serviceRegistry.all().map(e => e.service),
           indexPatterns,
           isOverwriteAllChecked
         );
         this.setState({
           loadingMessage: i18n.translate(
-            'kbn.management.objects.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage',
+            'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage',
             { defaultMessage: 'Retrying failed objects…' }
           ),
         });
         importCount += await saveObjects(
-          failedImports.map(({ obj }) => obj),
+          failedImports!.map(({ obj }) => obj) as any[],
           isOverwriteAllChecked
         );
       } catch (e) {
@@ -407,26 +436,26 @@ export class Flyout extends Component {
     this.setState({ status: 'success', importCount });
   };
 
-  onIndexChanged = (id, e) => {
+  onIndexChanged = (id: string, e: any) => {
     const value = e.target.value;
     this.setState(state => {
-      const conflictIndex = state.unmatchedReferences.findIndex(
+      const conflictIndex = state.unmatchedReferences?.findIndex(
         conflict => conflict.existingIndexPatternId === id
       );
-      if (conflictIndex === -1) {
+      if (conflictIndex === undefined || conflictIndex === -1) {
         return state;
       }
 
       return {
         unmatchedReferences: [
-          ...state.unmatchedReferences.slice(0, conflictIndex),
+          ...state.unmatchedReferences!.slice(0, conflictIndex),
           {
-            ...state.unmatchedReferences[conflictIndex],
+            ...state.unmatchedReferences![conflictIndex],
             newIndexPatternId: value,
           },
-          ...state.unmatchedReferences.slice(conflictIndex + 1),
+          ...state.unmatchedReferences!.slice(conflictIndex + 1),
         ],
-      };
+      } as any;
     });
   };
 
@@ -441,11 +470,11 @@ export class Flyout extends Component {
       {
         field: 'existingIndexPatternId',
         name: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdName',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdName',
           { defaultMessage: 'ID' }
         ),
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdDescription',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdDescription',
           { defaultMessage: 'ID of the index pattern' }
         ),
         sortable: true,
@@ -453,28 +482,28 @@ export class Flyout extends Component {
       {
         field: 'list',
         name: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountName',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountName',
           { defaultMessage: 'Count' }
         ),
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountDescription',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountDescription',
           { defaultMessage: 'How many affected objects' }
         ),
-        render: list => {
+        render: (list: any[]) => {
           return <Fragment>{list.length}</Fragment>;
         },
       },
       {
         field: 'list',
         name: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName',
           { defaultMessage: 'Sample of affected objects' }
         ),
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription',
           { defaultMessage: 'Sample of affected objects' }
         ),
-        render: list => {
+        render: (list: any[]) => {
           return (
             <ul style={{ listStyle: 'none' }}>
               {take(list, 3).map((obj, key) => (
@@ -487,15 +516,18 @@ export class Flyout extends Component {
       {
         field: 'existingIndexPatternId',
         name: i18n.translate(
-          'kbn.management.objects.objectsTable.flyout.renderConflicts.columnNewIndexPatternName',
+          'savedObjectsManagement.objectsTable.flyout.renderConflicts.columnNewIndexPatternName',
           { defaultMessage: 'New index pattern' }
         ),
-        render: id => {
-          const options = this.state.indexPatterns.map(indexPattern => ({
-            text: indexPattern.title,
-            value: indexPattern.id,
-            ['data-test-subj']: `indexPatternOption-${indexPattern.title}`,
-          }));
+        render: (id: string) => {
+          const options = this.state.indexPatterns!.map(
+            indexPattern =>
+              ({
+                text: indexPattern.title,
+                value: indexPattern.id,
+                'data-test-subj': `indexPatternOption-${indexPattern.title}`,
+              } as { text: string; value: string; 'data-test-subj'?: string })
+          );
 
           options.unshift({
             text: '-- Skip Import --',
@@ -518,7 +550,11 @@ export class Flyout extends Component {
     };
 
     return (
-      <EuiInMemoryTable items={unmatchedReferences} columns={columns} pagination={pagination} />
+      <EuiInMemoryTable
+        items={unmatchedReferences as any[]}
+        columns={columns}
+        pagination={pagination}
+      />
     );
   }
 
@@ -534,7 +570,7 @@ export class Flyout extends Component {
         <EuiCallOut
           title={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.errorCalloutTitle"
+              id="savedObjectsManagement.objectsTable.flyout.errorCalloutTitle"
               defaultMessage="Sorry, there was an error"
             />
           }
@@ -581,7 +617,7 @@ export class Flyout extends Component {
           data-test-subj="importSavedObjectsFailedWarning"
           title={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.importFailedTitle"
+              id="savedObjectsManagement.objectsTable.flyout.importFailedTitle"
               defaultMessage="Import failed"
             />
           }
@@ -590,7 +626,7 @@ export class Flyout extends Component {
         >
           <p>
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.importFailedDescription"
+              id="savedObjectsManagement.objectsTable.flyout.importFailedDescription"
               defaultMessage="Failed to import {failedImportCount} of {totalImportCount} objects. Import failed"
               values={{
                 failedImportCount: failedImports.length,
@@ -604,7 +640,7 @@ export class Flyout extends Component {
                 if (error.type === 'missing_references') {
                   return error.references.map(reference => {
                     return i18n.translate(
-                      'kbn.management.objects.objectsTable.flyout.importFailedMissingReference',
+                      'savedObjectsManagement.objectsTable.flyout.importFailedMissingReference',
                       {
                         defaultMessage: '{type} [id={id}] could not locate {refType} [id={refId}]',
                         values: {
@@ -618,7 +654,7 @@ export class Flyout extends Component {
                   });
                 } else if (error.type === 'unsupported_type') {
                   return i18n.translate(
-                    'kbn.management.objects.objectsTable.flyout.importFailedUnsupportedType',
+                    'savedObjectsManagement.objectsTable.flyout.importFailedUnsupportedType',
                     {
                       defaultMessage: '{type} [id={id}] unsupported type',
                       values: {
@@ -628,7 +664,7 @@ export class Flyout extends Component {
                     }
                   );
                 }
-                return getField(error, 'body.message', error.message || '');
+                return getField(error, 'body.message', (error as any).message ?? '');
               })
               .join(' ')}
           </p>
@@ -643,7 +679,7 @@ export class Flyout extends Component {
             data-test-subj="importSavedObjectsSuccessNoneImported"
             title={
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle"
+                id="savedObjectsManagement.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle"
                 defaultMessage="No objects imported"
               />
             }
@@ -657,7 +693,7 @@ export class Flyout extends Component {
           data-test-subj="importSavedObjectsSuccess"
           title={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.importSuccessfulTitle"
+              id="savedObjectsManagement.objectsTable.flyout.importSuccessfulTitle"
               defaultMessage="Import successful"
             />
           }
@@ -666,7 +702,7 @@ export class Flyout extends Component {
         >
           <p>
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.importSuccessfulDescription"
+              id="savedObjectsManagement.objectsTable.flyout.importSuccessfulDescription"
               defaultMessage="Successfully imported {importCount} objects."
               values={{ importCount }}
             />
@@ -684,7 +720,7 @@ export class Flyout extends Component {
         <EuiFormRow
           label={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.selectFileToImportFormRowLabel"
+              id="savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel"
               defaultMessage="Please select a file to import"
             />
           }
@@ -692,7 +728,7 @@ export class Flyout extends Component {
           <EuiFilePicker
             initialPromptText={
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.flyout.importPromptText"
+                id="savedObjectsManagement.objectsTable.flyout.importPromptText"
                 defaultMessage="Import"
               />
             }
@@ -704,7 +740,7 @@ export class Flyout extends Component {
             name="overwriteAll"
             label={
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.flyout.overwriteSavedObjectsLabel"
+                id="savedObjectsManagement.objectsTable.flyout.overwriteSavedObjectsLabel"
                 defaultMessage="Automatically overwrite all saved objects?"
               />
             }
@@ -727,7 +763,7 @@ export class Flyout extends Component {
       confirmButton = (
         <EuiButton onClick={done} size="s" fill data-test-subj="importSavedObjectsDoneBtn">
           <FormattedMessage
-            id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmButtonLabel"
             defaultMessage="Done"
           />
         </EuiButton>
@@ -742,7 +778,7 @@ export class Flyout extends Component {
           data-test-subj="importSavedObjectsConfirmBtn"
         >
           <FormattedMessage
-            id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
             defaultMessage="Confirm all changes"
           />
         </EuiButton>
@@ -757,7 +793,7 @@ export class Flyout extends Component {
           data-test-subj="importSavedObjectsImportBtn"
         >
           <FormattedMessage
-            id="kbn.management.objects.objectsTable.flyout.import.confirmButtonLabel"
+            id="savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel"
             defaultMessage="Import"
           />
         </EuiButton>
@@ -769,7 +805,7 @@ export class Flyout extends Component {
         <EuiFlexItem grow={false}>
           <EuiButtonEmpty onClick={close} size="s">
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
+              id="savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel"
               defaultMessage="Cancel"
             />
           </EuiButtonEmpty>
@@ -791,7 +827,7 @@ export class Flyout extends Component {
           data-test-subj="importSavedObjectsLegacyWarning"
           title={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.legacyFileUsedTitle"
+              id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle"
               defaultMessage="Support for JSON files is going away"
             />
           }
@@ -800,7 +836,7 @@ export class Flyout extends Component {
         >
           <p>
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.legacyFileUsedBody"
+              id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody"
               defaultMessage="Use our updated export to generate NDJSON files, and you'll be all set."
             />
           </p>
@@ -815,7 +851,7 @@ export class Flyout extends Component {
           data-test-subj="importSavedObjectsConflictsWarning"
           title={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
+              id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle"
               defaultMessage="Index Pattern Conflicts"
             />
           }
@@ -824,7 +860,7 @@ export class Flyout extends Component {
         >
           <p>
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
+              id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription"
               defaultMessage="The following saved objects use index patterns that do not exist.
               Please select the index patterns you'd like re-associated with
               them. You can {indexPatternLink} if necessary."
@@ -832,7 +868,7 @@ export class Flyout extends Component {
                 indexPatternLink: (
                   <EuiLink href={this.props.newIndexPatternUrl}>
                     <FormattedMessage
-                      id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
+                      id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
                       defaultMessage="create a new index pattern"
                     />
                   </EuiLink>
@@ -867,11 +903,11 @@ export class Flyout extends Component {
   }
 
   overwriteConfirmed() {
-    this.state.conflictingRecord.done(true);
+    this.state.conflictingRecord!.done(true);
   }
 
   overwriteSkipped() {
-    this.state.conflictingRecord.done(false);
+    this.state.conflictingRecord!.done(false);
   }
 
   render() {
@@ -883,18 +919,18 @@ export class Flyout extends Component {
         <EuiOverlayMask>
           <EuiConfirmModal
             title={i18n.translate(
-              'kbn.management.objects.objectsTable.flyout.confirmOverwriteTitle',
+              'savedObjectsManagement.objectsTable.flyout.confirmOverwriteTitle',
               {
                 defaultMessage: 'Overwrite {type}?',
                 values: { type: this.state.conflictingRecord.type },
               }
             )}
             cancelButtonText={i18n.translate(
-              'kbn.management.objects.objectsTable.flyout.confirmOverwriteCancelButtonText',
+              'savedObjectsManagement.objectsTable.flyout.confirmOverwriteCancelButtonText',
               { defaultMessage: 'Cancel' }
             )}
             confirmButtonText={i18n.translate(
-              'kbn.management.objects.objectsTable.flyout.confirmOverwriteOverwriteButtonText',
+              'savedObjectsManagement.objectsTable.flyout.confirmOverwriteOverwriteButtonText',
               { defaultMessage: 'Overwrite' }
             )}
             buttonColor="danger"
@@ -904,7 +940,7 @@ export class Flyout extends Component {
           >
             <p>
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.flyout.confirmOverwriteBody"
+                id="savedObjectsManagement.objectsTable.flyout.confirmOverwriteBody"
                 defaultMessage="Are you sure you want to overwrite {title}?"
                 values={{
                   title:
@@ -924,7 +960,7 @@ export class Flyout extends Component {
           <EuiTitle size="m">
             <h2>
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
+                id="savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle"
                 defaultMessage="Import saved objects"
               />
             </h2>
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.test.tsx
similarity index 96%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/header.test.tsx
index 1f501b5751224..891190d0bb24b 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.test.tsx
@@ -19,8 +19,7 @@
 
 import React from 'react';
 import { shallow } from 'enzyme';
-
-import { Header } from '../header';
+import { Header } from './header';
 
 describe('Header', () => {
   it('should render normally', () => {
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx
similarity index 83%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx
index 0bec8a0cf2daf..7a9584f08d632 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx
@@ -18,8 +18,6 @@
  */
 
 import React, { Fragment } from 'react';
-import PropTypes from 'prop-types';
-
 import {
   EuiSpacer,
   EuiTitle,
@@ -31,14 +29,24 @@ import {
 } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 
-export const Header = ({ onExportAll, onImport, onRefresh, filteredCount }) => (
+export const Header = ({
+  onExportAll,
+  onImport,
+  onRefresh,
+  filteredCount,
+}: {
+  onExportAll: () => void;
+  onImport: () => void;
+  onRefresh: () => void;
+  filteredCount: number;
+}) => (
   <Fragment>
     <EuiFlexGroup justifyContent="spaceBetween" alignItems="baseline">
       <EuiFlexItem grow={false}>
         <EuiTitle>
           <h1>
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.header.savedObjectsTitle"
+              id="savedObjectsManagement.objectsTable.header.savedObjectsTitle"
               defaultMessage="Saved Objects"
             />
           </h1>
@@ -55,7 +63,7 @@ export const Header = ({ onExportAll, onImport, onRefresh, filteredCount }) => (
               onClick={onExportAll}
             >
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.header.exportButtonLabel"
+                id="savedObjectsManagement.objectsTable.header.exportButtonLabel"
                 defaultMessage="Export {filteredCount, plural, one{# object} other {# objects}}"
                 values={{
                   filteredCount,
@@ -71,7 +79,7 @@ export const Header = ({ onExportAll, onImport, onRefresh, filteredCount }) => (
               onClick={onImport}
             >
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.header.importButtonLabel"
+                id="savedObjectsManagement.objectsTable.header.importButtonLabel"
                 defaultMessage="Import"
               />
             </EuiButtonEmpty>
@@ -79,7 +87,7 @@ export const Header = ({ onExportAll, onImport, onRefresh, filteredCount }) => (
           <EuiFlexItem grow={false}>
             <EuiButtonEmpty size="s" iconType="refresh" onClick={onRefresh}>
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.header.refreshButtonLabel"
+                id="savedObjectsManagement.objectsTable.header.refreshButtonLabel"
                 defaultMessage="Refresh"
               />
             </EuiButtonEmpty>
@@ -92,7 +100,7 @@ export const Header = ({ onExportAll, onImport, onRefresh, filteredCount }) => (
       <p>
         <EuiTextColor color="subdued">
           <FormattedMessage
-            id="kbn.management.objects.objectsTable.howToDeleteSavedObjectsDescription"
+            id="savedObjectsManagement.objectsTable.howToDeleteSavedObjectsDescription"
             defaultMessage="From here you can delete saved objects, such as saved searches.
             You can also edit the raw data of saved objects.
             Typically objects are only modified via their associated application,
@@ -104,10 +112,3 @@ export const Header = ({ onExportAll, onImport, onRefresh, filteredCount }) => (
     <EuiSpacer size="m" />
   </Fragment>
 );
-
-Header.propTypes = {
-  onExportAll: PropTypes.func.isRequired,
-  onImport: PropTypes.func.isRequired,
-  onRefresh: PropTypes.func.isRequired,
-  filteredCount: PropTypes.number.isRequired,
-};
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/index.ts b/src/plugins/saved_objects_management/public/management_section/objects_table/components/index.ts
new file mode 100644
index 0000000000000..9c8736a9011eb
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/index.ts
@@ -0,0 +1,23 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export { Header } from './header';
+export { Table } from './table';
+export { Flyout } from './flyout';
+export { Relationships } from './relationships';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx
similarity index 88%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx
index 479726e8785d8..347f2d977015c 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx
@@ -19,27 +19,23 @@
 
 import React from 'react';
 import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
+import { httpServiceMock } from '../../../../../../core/public/mocks';
+import { Relationships, RelationshipsProps } from './relationships';
 
-jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
-
-jest.mock('ui/chrome', () => ({
-  addBasePath: () => '',
-}));
-
-jest.mock('../../../../../lib/fetch_export_by_type_and_search', () => ({
+jest.mock('../../../lib/fetch_export_by_type_and_search', () => ({
   fetchExportByTypeAndSearch: jest.fn(),
 }));
 
-jest.mock('../../../../../lib/fetch_export_objects', () => ({
+jest.mock('../../../lib/fetch_export_objects', () => ({
   fetchExportObjects: jest.fn(),
 }));
 
-import { Relationships } from '../relationships';
-
 describe('Relationships', () => {
   it('should render index patterns normally', async () => {
-    const props = {
+    const props: RelationshipsProps = {
       goInspectObject: () => {},
+      canGoInApp: () => true,
+      basePath: httpServiceMock.createSetupContract().basePath,
       getRelationships: jest.fn().mockImplementation(() => [
         {
           type: 'search',
@@ -73,6 +69,8 @@ describe('Relationships', () => {
       savedObject: {
         id: '1',
         type: 'index-pattern',
+        attributes: {},
+        references: [],
         meta: {
           title: 'MyIndexPattern*',
           icon: 'indexPatternApp',
@@ -101,8 +99,10 @@ describe('Relationships', () => {
   });
 
   it('should render searches normally', async () => {
-    const props = {
+    const props: RelationshipsProps = {
       goInspectObject: () => {},
+      canGoInApp: () => true,
+      basePath: httpServiceMock.createSetupContract().basePath,
       getRelationships: jest.fn().mockImplementation(() => [
         {
           type: 'index-pattern',
@@ -136,6 +136,8 @@ describe('Relationships', () => {
       savedObject: {
         id: '1',
         type: 'search',
+        attributes: {},
+        references: [],
         meta: {
           title: 'MySearch',
           icon: 'search',
@@ -164,8 +166,10 @@ describe('Relationships', () => {
   });
 
   it('should render visualizations normally', async () => {
-    const props = {
+    const props: RelationshipsProps = {
       goInspectObject: () => {},
+      canGoInApp: () => true,
+      basePath: httpServiceMock.createSetupContract().basePath,
       getRelationships: jest.fn().mockImplementation(() => [
         {
           type: 'dashboard',
@@ -199,6 +203,8 @@ describe('Relationships', () => {
       savedObject: {
         id: '1',
         type: 'visualization',
+        attributes: {},
+        references: [],
         meta: {
           title: 'MyViz',
           icon: 'visualizeApp',
@@ -227,8 +233,10 @@ describe('Relationships', () => {
   });
 
   it('should render dashboards normally', async () => {
-    const props = {
+    const props: RelationshipsProps = {
       goInspectObject: () => {},
+      canGoInApp: () => true,
+      basePath: httpServiceMock.createSetupContract().basePath,
       getRelationships: jest.fn().mockImplementation(() => [
         {
           type: 'visualization',
@@ -262,6 +270,8 @@ describe('Relationships', () => {
       savedObject: {
         id: '1',
         type: 'dashboard',
+        attributes: {},
+        references: [],
         meta: {
           title: 'MyDashboard',
           icon: 'dashboardApp',
@@ -290,14 +300,18 @@ describe('Relationships', () => {
   });
 
   it('should render errors', async () => {
-    const props = {
+    const props: RelationshipsProps = {
       goInspectObject: () => {},
+      canGoInApp: () => true,
+      basePath: httpServiceMock.createSetupContract().basePath,
       getRelationships: jest.fn().mockImplementation(() => {
         throw new Error('foo');
       }),
       savedObject: {
         id: '1',
         type: 'dashboard',
+        attributes: {},
+        references: [],
         meta: {
           title: 'MyDashboard',
           icon: 'dashboardApp',
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx
similarity index 75%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx
index ce3415ad2f0e7..ddb262138d565 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx
@@ -18,8 +18,6 @@
  */
 
 import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-
 import {
   EuiTitle,
   EuiFlyout,
@@ -34,25 +32,34 @@ import {
   EuiText,
   EuiSpacer,
 } from '@elastic/eui';
-import chrome from 'ui/chrome';
+import { FilterConfig } from '@elastic/eui/src/components/search_bar/filters/filters';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-import { getDefaultTitle, getSavedObjectLabel } from '../../../../lib';
+import { IBasePath } from 'src/core/public';
+import { getDefaultTitle, getSavedObjectLabel } from '../../../lib';
+import { SavedObjectWithMetadata, SavedObjectRelation } from '../../../types';
+
+export interface RelationshipsProps {
+  basePath: IBasePath;
+  getRelationships: (type: string, id: string) => Promise<SavedObjectRelation[]>;
+  savedObject: SavedObjectWithMetadata;
+  close: () => void;
+  goInspectObject: (obj: SavedObjectWithMetadata) => void;
+  canGoInApp: (obj: SavedObjectWithMetadata) => boolean;
+}
 
-export class Relationships extends Component {
-  static propTypes = {
-    getRelationships: PropTypes.func.isRequired,
-    savedObject: PropTypes.object.isRequired,
-    close: PropTypes.func.isRequired,
-    goInspectObject: PropTypes.func.isRequired,
-    canGoInApp: PropTypes.func.isRequired,
-  };
+export interface RelationshipsState {
+  relationships: SavedObjectRelation[];
+  isLoading: boolean;
+  error?: string;
+}
 
-  constructor(props) {
+export class Relationships extends Component<RelationshipsProps, RelationshipsState> {
+  constructor(props: RelationshipsProps) {
     super(props);
 
     this.state = {
-      relationships: undefined,
+      relationships: [],
       isLoading: false,
       error: undefined,
     };
@@ -62,7 +69,7 @@ export class Relationships extends Component {
     this.getRelationshipData();
   }
 
-  UNSAFE_componentWillReceiveProps(nextProps) {
+  UNSAFE_componentWillReceiveProps(nextProps: RelationshipsProps) {
     if (nextProps.savedObject.id !== this.props.savedObject.id) {
       this.getRelationshipData();
     }
@@ -92,7 +99,7 @@ export class Relationships extends Component {
       <EuiCallOut
         title={
           <FormattedMessage
-            id="kbn.management.objects.objectsTable.relationships.renderErrorMessage"
+            id="savedObjectsManagement.objectsTable.relationships.renderErrorMessage"
             defaultMessage="Error"
           />
         }
@@ -104,7 +111,7 @@ export class Relationships extends Component {
   }
 
   renderRelationships() {
-    const { goInspectObject, savedObject } = this.props;
+    const { goInspectObject, savedObject, basePath } = this.props;
     const { relationships, isLoading, error } = this.state;
 
     if (error) {
@@ -118,17 +125,17 @@ export class Relationships extends Component {
     const columns = [
       {
         field: 'type',
-        name: i18n.translate('kbn.management.objects.objectsTable.relationships.columnTypeName', {
+        name: i18n.translate('savedObjectsManagement.objectsTable.relationships.columnTypeName', {
           defaultMessage: 'Type',
         }),
         width: '50px',
         align: 'center',
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.relationships.columnTypeDescription',
+          'savedObjectsManagement.objectsTable.relationships.columnTypeDescription',
           { defaultMessage: 'Type of the saved object' }
         ),
         sortable: false,
-        render: (type, object) => {
+        render: (type: string, object: SavedObjectWithMetadata) => {
           return (
             <EuiToolTip position="top" content={getSavedObjectLabel(type)}>
               <EuiIcon
@@ -144,19 +151,19 @@ export class Relationships extends Component {
       {
         field: 'relationship',
         name: i18n.translate(
-          'kbn.management.objects.objectsTable.relationships.columnRelationshipName',
+          'savedObjectsManagement.objectsTable.relationships.columnRelationshipName',
           { defaultMessage: 'Direct relationship' }
         ),
         dataType: 'string',
         sortable: false,
         width: '125px',
         'data-test-subj': 'directRelationship',
-        render: relationship => {
+        render: (relationship: string) => {
           if (relationship === 'parent') {
             return (
               <EuiText size="s">
                 <FormattedMessage
-                  id="kbn.management.objects.objectsTable.relationships.columnRelationship.parentAsValue"
+                  id="savedObjectsManagement.objectsTable.relationships.columnRelationship.parentAsValue"
                   defaultMessage="Parent"
                 />
               </EuiText>
@@ -166,7 +173,7 @@ export class Relationships extends Component {
             return (
               <EuiText size="s">
                 <FormattedMessage
-                  id="kbn.management.objects.objectsTable.relationships.columnRelationship.childAsValue"
+                  id="savedObjectsManagement.objectsTable.relationships.columnRelationship.childAsValue"
                   defaultMessage="Child"
                 />
               </EuiText>
@@ -176,17 +183,17 @@ export class Relationships extends Component {
       },
       {
         field: 'meta.title',
-        name: i18n.translate('kbn.management.objects.objectsTable.relationships.columnTitleName', {
+        name: i18n.translate('savedObjectsManagement.objectsTable.relationships.columnTitleName', {
           defaultMessage: 'Title',
         }),
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.relationships.columnTitleDescription',
+          'savedObjectsManagement.objectsTable.relationships.columnTitleDescription',
           { defaultMessage: 'Title of the saved object' }
         ),
         dataType: 'string',
         sortable: false,
-        render: (title, object) => {
-          const { path } = object.meta.inAppUrl || {};
+        render: (title: string, object: SavedObjectWithMetadata) => {
+          const { path = '' } = object.meta.inAppUrl || {};
           const canGoInApp = this.props.canGoInApp(object);
           if (!canGoInApp) {
             return (
@@ -196,7 +203,7 @@ export class Relationships extends Component {
             );
           }
           return (
-            <EuiLink href={chrome.addBasePath(path)} data-test-subj="relationshipsTitle">
+            <EuiLink href={basePath.prepend(path)} data-test-subj="relationshipsTitle">
               {title || getDefaultTitle(object)}
             </EuiLink>
           );
@@ -204,24 +211,24 @@ export class Relationships extends Component {
       },
       {
         name: i18n.translate(
-          'kbn.management.objects.objectsTable.relationships.columnActionsName',
+          'savedObjectsManagement.objectsTable.relationships.columnActionsName',
           { defaultMessage: 'Actions' }
         ),
         actions: [
           {
             name: i18n.translate(
-              'kbn.management.objects.objectsTable.relationships.columnActions.inspectActionName',
+              'savedObjectsManagement.objectsTable.relationships.columnActions.inspectActionName',
               { defaultMessage: 'Inspect' }
             ),
             description: i18n.translate(
-              'kbn.management.objects.objectsTable.relationships.columnActions.inspectActionDescription',
+              'savedObjectsManagement.objectsTable.relationships.columnActions.inspectActionDescription',
               { defaultMessage: 'Inspect this saved object' }
             ),
             type: 'icon',
             icon: 'inspect',
             'data-test-subj': 'relationshipsTableAction-inspect',
-            onClick: object => goInspectObject(object),
-            available: object => !!object.meta.editUrl,
+            onClick: (object: SavedObjectWithMetadata) => goInspectObject(object),
+            available: (object: SavedObjectWithMetadata) => !!object.meta.editUrl,
           },
         ],
       },
@@ -244,7 +251,7 @@ export class Relationships extends Component {
           type: 'field_value_selection',
           field: 'relationship',
           name: i18n.translate(
-            'kbn.management.objects.objectsTable.relationships.search.filters.relationship.name',
+            'savedObjectsManagement.objectsTable.relationships.search.filters.relationship.name',
             { defaultMessage: 'Direct relationship' }
           ),
           multiSelect: 'or',
@@ -253,7 +260,7 @@ export class Relationships extends Component {
               value: 'parent',
               name: 'parent',
               view: i18n.translate(
-                'kbn.management.objects.objectsTable.relationships.search.filters.relationship.parentAsValue.view',
+                'savedObjectsManagement.objectsTable.relationships.search.filters.relationship.parentAsValue.view',
                 { defaultMessage: 'Parent' }
               ),
             },
@@ -261,7 +268,7 @@ export class Relationships extends Component {
               value: 'child',
               name: 'child',
               view: i18n.translate(
-                'kbn.management.objects.objectsTable.relationships.search.filters.relationship.childAsValue.view',
+                'savedObjectsManagement.objectsTable.relationships.search.filters.relationship.childAsValue.view',
                 { defaultMessage: 'Child' }
               ),
             },
@@ -271,13 +278,13 @@ export class Relationships extends Component {
           type: 'field_value_selection',
           field: 'type',
           name: i18n.translate(
-            'kbn.management.objects.objectsTable.relationships.search.filters.type.name',
+            'savedObjectsManagement.objectsTable.relationships.search.filters.type.name',
             { defaultMessage: 'Type' }
           ),
           multiSelect: 'or',
           options: [...filterTypesMap.values()],
         },
-      ],
+      ] as FilterConfig[],
     };
 
     return (
@@ -285,7 +292,7 @@ export class Relationships extends Component {
         <EuiCallOut>
           <p>
             {i18n.translate(
-              'kbn.management.objects.objectsTable.relationships.relationshipsTitle',
+              'savedObjectsManagement.objectsTable.relationships.relationshipsTitle',
               {
                 defaultMessage:
                   'Here are the saved objects related to {title}. ' +
@@ -301,7 +308,7 @@ export class Relationships extends Component {
         <EuiSpacer />
         <EuiInMemoryTable
           items={relationships}
-          columns={columns}
+          columns={columns as any}
           pagination={true}
           search={search}
           rowProps={() => ({
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx
similarity index 87%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx
index 9b3e2314c9f84..356f227773610 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx
@@ -19,27 +19,22 @@
 
 import React from 'react';
 import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers';
+// @ts-ignore
 import { findTestSubject } from '@elastic/eui/lib/test';
-import { keyCodes } from '@elastic/eui/lib/services';
-import { npSetup as mockNpSetup } from '../../../../../../../../../../../ui/public/new_platform/__mocks__';
+import { keyCodes } from '@elastic/eui';
+import { httpServiceMock } from '../../../../../../core/public/mocks';
+import { actionServiceMock } from '../../../services/action_service.mock';
+import { Table, TableProps } from './table';
 
-jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
-
-jest.mock('ui/chrome', () => ({
-  addBasePath: () => '',
-}));
-
-jest.mock('ui/new_platform', () => ({
-  npSetup: mockNpSetup,
-}));
-
-import { Table } from '../table';
-
-const defaultProps = {
+const defaultProps: TableProps = {
+  basePath: httpServiceMock.createSetupContract().basePath,
+  actionRegistry: actionServiceMock.createStart(),
   selectedSavedObjects: [
     {
       id: '1',
       type: 'index-pattern',
+      attributes: {},
+      references: [],
       meta: {
         title: `MyIndexPattern*`,
         icon: 'indexPatternApp',
@@ -58,13 +53,15 @@ const defaultProps = {
   onDelete: () => {},
   onExport: () => {},
   goInspectObject: () => {},
-  canGoInApp: () => {},
+  canGoInApp: () => true,
   pageIndex: 1,
   pageSize: 2,
   items: [
     {
       id: '1',
       type: 'index-pattern',
+      attributes: {},
+      references: [],
       meta: {
         title: `MyIndexPattern*`,
         icon: 'indexPatternApp',
@@ -120,7 +117,7 @@ describe('Table', () => {
       { type: 'visualization' },
       { type: 'search' },
       { type: 'index-pattern' },
-    ];
+    ] as any;
     const customizedProps = { ...defaultProps, selectedSavedObjects, canDelete: false };
     const component = shallowWithI18nProvider(<Table {...customizedProps} />);
 
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
similarity index 71%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
index 132fa1e691c1c..5b574e4b3d331 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
@@ -17,12 +17,10 @@
  * under the License.
  */
 
-import chrome from 'ui/chrome';
-import { npSetup } from 'ui/new_platform';
+import { IBasePath } from 'src/core/public';
 import React, { PureComponent, Fragment } from 'react';
-import PropTypes from 'prop-types';
-
 import {
+  // @ts-ignore
   EuiSearchBar,
   EuiBasicTable,
   EuiButton,
@@ -35,54 +33,64 @@ import {
   EuiSwitch,
   EuiFormRow,
   EuiText,
+  EuiTableFieldDataColumnType,
+  EuiTableActionsColumnType,
 } from '@elastic/eui';
-import { getDefaultTitle, getSavedObjectLabel } from '../../../../lib';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
+import { getDefaultTitle, getSavedObjectLabel } from '../../../lib';
+import { SavedObjectWithMetadata } from '../../../types';
+import {
+  SavedObjectsManagementActionServiceStart,
+  SavedObjectsManagementAction,
+} from '../../../services';
 
-export class Table extends PureComponent {
-  static propTypes = {
-    selectedSavedObjects: PropTypes.array.isRequired,
-    selectionConfig: PropTypes.shape({
-      selectable: PropTypes.func,
-      selectableMessage: PropTypes.func,
-      onSelectionChange: PropTypes.func.isRequired,
-    }).isRequired,
-    filterOptions: PropTypes.array.isRequired,
-    canDelete: PropTypes.bool.isRequired,
-    onDelete: PropTypes.func.isRequired,
-    onExport: PropTypes.func.isRequired,
-    goInspectObject: PropTypes.func.isRequired,
-
-    pageIndex: PropTypes.number.isRequired,
-    pageSize: PropTypes.number.isRequired,
-    items: PropTypes.array.isRequired,
-    itemId: PropTypes.oneOfType([
-      PropTypes.string, // the name of the item id property
-      PropTypes.func, // (item) => string
-    ]),
-    totalItemCount: PropTypes.number.isRequired,
-    onQueryChange: PropTypes.func.isRequired,
-    onTableChange: PropTypes.func.isRequired,
-    isSearching: PropTypes.bool.isRequired,
-
-    onShowRelationships: PropTypes.func.isRequired,
+export interface TableProps {
+  basePath: IBasePath;
+  actionRegistry: SavedObjectsManagementActionServiceStart;
+  selectedSavedObjects: SavedObjectWithMetadata[];
+  selectionConfig: {
+    onSelectionChange: (selection: SavedObjectWithMetadata[]) => void;
   };
+  filterOptions: any[];
+  canDelete: boolean;
+  onDelete: () => void;
+  onExport: (includeReferencesDeep: boolean) => void;
+  goInspectObject: (obj: SavedObjectWithMetadata) => void;
+  pageIndex: number;
+  pageSize: number;
+  items: SavedObjectWithMetadata[];
+  itemId: string | (() => string);
+  totalItemCount: number;
+  onQueryChange: (query: any) => void;
+  onTableChange: (table: any) => void;
+  isSearching: boolean;
+  onShowRelationships: (object: SavedObjectWithMetadata) => void;
+  canGoInApp: (obj: SavedObjectWithMetadata) => boolean;
+}
+
+interface TableState {
+  isSearchTextValid: boolean;
+  parseErrorMessage: any;
+  isExportPopoverOpen: boolean;
+  isIncludeReferencesDeepChecked: boolean;
+  activeAction?: SavedObjectsManagementAction;
+}
 
-  state = {
+export class Table extends PureComponent<TableProps, TableState> {
+  state: TableState = {
     isSearchTextValid: true,
     parseErrorMessage: null,
     isExportPopoverOpen: false,
     isIncludeReferencesDeepChecked: true,
-    activeAction: null,
+    activeAction: undefined,
   };
 
-  constructor(props) {
+  constructor(props: TableProps) {
     super(props);
-    this.extraActions = npSetup.plugins.savedObjectsManagement.actionRegistry.getAll();
   }
 
-  onChange = ({ query, error }) => {
+  onChange = ({ query, error }: any) => {
     if (error) {
       this.setState({
         isSearchTextValid: false,
@@ -136,12 +144,14 @@ export class Table extends PureComponent {
       onTableChange,
       goInspectObject,
       onShowRelationships,
+      basePath,
+      actionRegistry,
     } = this.props;
 
     const pagination = {
-      pageIndex: pageIndex,
-      pageSize: pageSize,
-      totalItemCount: totalItemCount,
+      pageIndex,
+      pageSize,
+      totalItemCount,
       pageSizeOptions: [5, 10, 20, 50],
     };
 
@@ -149,7 +159,7 @@ export class Table extends PureComponent {
       {
         type: 'field_value_selection',
         field: 'type',
-        name: i18n.translate('kbn.management.objects.objectsTable.table.typeFilterName', {
+        name: i18n.translate('savedObjectsManagement.objectsTable.table.typeFilterName', {
           defaultMessage: 'Type',
         }),
         multiSelect: 'or',
@@ -168,18 +178,18 @@ export class Table extends PureComponent {
     const columns = [
       {
         field: 'type',
-        name: i18n.translate('kbn.management.objects.objectsTable.table.columnTypeName', {
+        name: i18n.translate('savedObjectsManagement.objectsTable.table.columnTypeName', {
           defaultMessage: 'Type',
         }),
         width: '50px',
         align: 'center',
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.table.columnTypeDescription',
+          'savedObjectsManagement.objectsTable.table.columnTypeDescription',
           { defaultMessage: 'Type of the saved object' }
         ),
         sortable: false,
         'data-test-subj': 'savedObjectsTableRowType',
-        render: (type, object) => {
+        render: (type: string, object: SavedObjectWithMetadata) => {
           return (
             <EuiToolTip position="top" content={getSavedObjectLabel(type)}>
               <EuiIcon
@@ -191,42 +201,42 @@ export class Table extends PureComponent {
             </EuiToolTip>
           );
         },
-      },
+      } as EuiTableFieldDataColumnType<SavedObjectWithMetadata<any>>,
       {
         field: 'meta.title',
-        name: i18n.translate('kbn.management.objects.objectsTable.table.columnTitleName', {
+        name: i18n.translate('savedObjectsManagement.objectsTable.table.columnTitleName', {
           defaultMessage: 'Title',
         }),
         description: i18n.translate(
-          'kbn.management.objects.objectsTable.table.columnTitleDescription',
+          'savedObjectsManagement.objectsTable.table.columnTitleDescription',
           { defaultMessage: 'Title of the saved object' }
         ),
         dataType: 'string',
         sortable: false,
         'data-test-subj': 'savedObjectsTableRowTitle',
-        render: (title, object) => {
-          const { path } = object.meta.inAppUrl || {};
+        render: (title: string, object: SavedObjectWithMetadata) => {
+          const { path = '' } = object.meta.inAppUrl || {};
           const canGoInApp = this.props.canGoInApp(object);
           if (!canGoInApp) {
             return <EuiText size="s">{title || getDefaultTitle(object)}</EuiText>;
           }
           return (
-            <EuiLink href={chrome.addBasePath(path)}>{title || getDefaultTitle(object)}</EuiLink>
+            <EuiLink href={basePath.prepend(path)}>{title || getDefaultTitle(object)}</EuiLink>
           );
         },
-      },
+      } as EuiTableFieldDataColumnType<SavedObjectWithMetadata<any>>,
       {
-        name: i18n.translate('kbn.management.objects.objectsTable.table.columnActionsName', {
+        name: i18n.translate('savedObjectsManagement.objectsTable.table.columnActionsName', {
           defaultMessage: 'Actions',
         }),
         actions: [
           {
             name: i18n.translate(
-              'kbn.management.objects.objectsTable.table.columnActions.inspectActionName',
+              'savedObjectsManagement.objectsTable.table.columnActions.inspectActionName',
               { defaultMessage: 'Inspect' }
             ),
             description: i18n.translate(
-              'kbn.management.objects.objectsTable.table.columnActions.inspectActionDescription',
+              'savedObjectsManagement.objectsTable.table.columnActions.inspectActionDescription',
               { defaultMessage: 'Inspect this saved object' }
             ),
             type: 'icon',
@@ -237,11 +247,11 @@ export class Table extends PureComponent {
           },
           {
             name: i18n.translate(
-              'kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionName',
+              'savedObjectsManagement.objectsTable.table.columnActions.viewRelationshipsActionName',
               { defaultMessage: 'Relationships' }
             ),
             description: i18n.translate(
-              'kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionDescription',
+              'savedObjectsManagement.objectsTable.table.columnActions.viewRelationshipsActionDescription',
               {
                 defaultMessage:
                   'View the relationships this saved object has to other saved objects',
@@ -252,33 +262,35 @@ export class Table extends PureComponent {
             onClick: object => onShowRelationships(object),
             'data-test-subj': 'savedObjectsTableAction-relationships',
           },
-          ...this.extraActions.map(action => {
+          ...actionRegistry.getAll().map(action => {
             return {
               ...action.euiAction,
               'data-test-subj': `savedObjectsTableAction-${action.id}`,
-              onClick: object => {
+              onClick: (object: SavedObjectWithMetadata) => {
                 this.setState({
                   activeAction: action,
                 });
 
                 action.registerOnFinishCallback(() => {
                   this.setState({
-                    activeAction: null,
+                    activeAction: undefined,
                   });
                 });
 
-                action.euiAction.onClick(object);
+                if (action.euiAction.onClick) {
+                  action.euiAction.onClick(object as any);
+                }
               },
             };
           }),
         ],
-      },
+      } as EuiTableActionsColumnType<SavedObjectWithMetadata>,
     ];
 
     let queryParseError;
     if (!this.state.isSearchTextValid) {
       const parseErrorMsg = i18n.translate(
-        'kbn.management.objects.objectsTable.searchBar.unableToParseQueryErrorMessage',
+        'savedObjectsManagement.objectsTable.searchBar.unableToParseQueryErrorMessage',
         { defaultMessage: 'Unable to parse query' }
       );
       queryParseError = (
@@ -294,20 +306,20 @@ export class Table extends PureComponent {
         isDisabled={selectedSavedObjects.length === 0}
       >
         <FormattedMessage
-          id="kbn.management.objects.objectsTable.table.exportPopoverButtonLabel"
+          id="savedObjectsManagement.objectsTable.table.exportPopoverButtonLabel"
           defaultMessage="Export"
         />
       </EuiButton>
     );
 
-    const activeActionContents = this.state.activeAction ? this.state.activeAction.render() : null;
+    const activeActionContents = this.state.activeAction?.render() ?? null;
 
     return (
       <Fragment>
         {activeActionContents}
         <EuiSearchBar
           box={{ 'data-test-subj': 'savedObjectSearchBar' }}
-          filters={filters}
+          filters={filters as any}
           onChange={this.onChange}
           toolsRight={[
             <EuiButton
@@ -319,14 +331,14 @@ export class Table extends PureComponent {
               title={
                 this.props.canDelete
                   ? undefined
-                  : i18n.translate('kbn.management.objects.objectsTable.table.deleteButtonTitle', {
+                  : i18n.translate('savedObjectsManagement.objectsTable.table.deleteButtonTitle', {
                       defaultMessage: 'Unable to delete saved objects',
                     })
               }
               data-test-subj="savedObjectsManagementDelete"
             >
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.table.deleteButtonLabel"
+                id="savedObjectsManagement.objectsTable.table.deleteButtonLabel"
                 defaultMessage="Delete"
               />
             </EuiButton>,
@@ -339,7 +351,7 @@ export class Table extends PureComponent {
               <EuiFormRow
                 label={
                   <FormattedMessage
-                    id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportOptionsLabel"
+                    id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportOptionsLabel"
                     defaultMessage="Options"
                   />
                 }
@@ -348,7 +360,7 @@ export class Table extends PureComponent {
                   name="includeReferencesDeep"
                   label={
                     <FormattedMessage
-                      id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
+                      id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
                       defaultMessage="Include related objects"
                     />
                   }
@@ -359,7 +371,7 @@ export class Table extends PureComponent {
               <EuiFormRow>
                 <EuiButton key="exportSO" iconType="exportAction" onClick={this.onExportClick} fill>
                   <FormattedMessage
-                    id="kbn.management.objects.objectsTable.table.exportButtonLabel"
+                    id="savedObjectsManagement.objectsTable.table.exportButtonLabel"
                     defaultMessage="Export"
                   />
                 </EuiButton>
@@ -374,7 +386,7 @@ export class Table extends PureComponent {
             loading={isSearching}
             itemId={itemId}
             items={items}
-            columns={columns}
+            columns={columns as any}
             pagination={pagination}
             selection={selection}
             onChange={onTableChange}
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/index.js b/src/plugins/saved_objects_management/public/management_section/objects_table/index.ts
similarity index 93%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/index.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/index.ts
index e1195c6edfe31..8777b15389690 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/index.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/index.ts
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-export { Table } from './table';
+export { SavedObjectsTable } from './saved_objects_table';
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.mocks.ts b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.mocks.ts
new file mode 100644
index 0000000000000..6b4659a6b5a13
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.mocks.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.
+ */
+
+export const saveAsMock = jest.fn();
+jest.doMock('@elastic/filesaver', () => ({
+  saveAs: saveAsMock,
+}));
+
+jest.doMock('lodash', () => ({
+  ...jest.requireActual('lodash'),
+  debounce: (func: Function) => {
+    function debounced(this: any, ...args: any[]) {
+      return func.apply(this, args);
+    }
+    return debounced;
+  },
+}));
+
+export const findObjectsMock = jest.fn();
+jest.doMock('../../lib/find_objects', () => ({
+  findObjects: findObjectsMock,
+}));
+
+export const fetchExportObjectsMock = jest.fn();
+jest.doMock('../../lib/fetch_export_objects', () => ({
+  fetchExportObjects: fetchExportObjectsMock,
+}));
+
+export const fetchExportByTypeAndSearchMock = jest.fn();
+jest.doMock('../../lib/fetch_export_by_type_and_search', () => ({
+  fetchExportByTypeAndSearch: fetchExportByTypeAndSearchMock,
+}));
+
+export const extractExportDetailsMock = jest.fn();
+jest.doMock('../../lib/extract_export_details', () => ({
+  extractExportDetails: extractExportDetailsMock,
+}));
+
+jest.doMock('./components/header', () => ({
+  Header: () => 'Header',
+}));
+
+export const getSavedObjectCountsMock = jest.fn();
+jest.doMock('../../lib/get_saved_object_counts', () => ({
+  getSavedObjectCounts: getSavedObjectCountsMock,
+}));
+
+export const getRelationshipsMock = jest.fn();
+jest.doMock('../../lib/get_relationships', () => ({
+  getRelationships: getRelationshipsMock,
+}));
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx
similarity index 58%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx
index 7b9c17640a0f3..342fdc4784b09 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx
@@ -17,69 +17,39 @@
  * under the License.
  */
 
+import {
+  extractExportDetailsMock,
+  fetchExportByTypeAndSearchMock,
+  fetchExportObjectsMock,
+  findObjectsMock,
+  getRelationshipsMock,
+  getSavedObjectCountsMock,
+  saveAsMock,
+} from './saved_objects_table.test.mocks';
+
 import React from 'react';
-import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
-import { mockManagementPlugin } from '../../../../../../../../../../plugins/index_pattern_management/public/mocks';
 import { Query } from '@elastic/eui';
-
-import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table';
-import { Flyout } from '../components/flyout/';
-import { Relationships } from '../components/relationships/';
-import { findObjects } from '../../../lib';
-import { extractExportDetails } from '../../../lib/extract_export_details';
-
-jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
-
-jest.mock('../../../../../../../../../../plugins/index_pattern_management/public', () => ({
-  setup: mockManagementPlugin.createSetupContract(),
-  start: mockManagementPlugin.createStartContract(),
-}));
-
-jest.mock('../../../lib/find_objects', () => ({
-  findObjects: jest.fn(),
-}));
-
-jest.mock('../components/header', () => ({
-  Header: () => 'Header',
-}));
-
-jest.mock('ui/chrome', () => ({
-  addBasePath: () => '',
-  getInjected: () => ['index-pattern', 'visualization', 'dashboard', 'search'],
-}));
-
-jest.mock('../../../lib/fetch_export_objects', () => ({
-  fetchExportObjects: jest.fn(),
-}));
-
-jest.mock('../../../lib/fetch_export_by_type_and_search', () => ({
-  fetchExportByTypeAndSearch: jest.fn(),
-}));
-
-jest.mock('../../../lib/extract_export_details', () => ({
-  extractExportDetails: jest.fn(),
-}));
-
-jest.mock('../../../lib/get_saved_object_counts', () => ({
-  getSavedObjectCounts: jest.fn().mockImplementation(() => {
-    return {
-      'index-pattern': 0,
-      visualization: 0,
-      dashboard: 0,
-      search: 0,
-    };
-  }),
-}));
-
-jest.mock('@elastic/filesaver', () => ({
-  saveAs: jest.fn(),
-}));
-
-jest.mock('../../../lib/get_relationships', () => ({
-  getRelationships: jest.fn(),
-}));
-
-jest.mock('ui/notify', () => ({}));
+import { ShallowWrapper } from 'enzyme';
+import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
+import {
+  httpServiceMock,
+  overlayServiceMock,
+  notificationServiceMock,
+  savedObjectsServiceMock,
+  applicationServiceMock,
+} from '../../../../../core/public/mocks';
+import { dataPluginMock } from '../../../../data/public/mocks';
+import { serviceRegistryMock } from '../../services/service_registry.mock';
+import { actionServiceMock } from '../../services/action_service.mock';
+import {
+  SavedObjectsTable,
+  SavedObjectsTableProps,
+  SavedObjectsTableState,
+} from './saved_objects_table';
+import { Flyout, Relationships } from './components';
+import { SavedObjectWithMetadata } from '../../types';
+
+const allowedTypes = ['index-pattern', 'visualization', 'dashboard', 'search'];
 
 const allSavedObjects = [
   {
@@ -112,122 +82,128 @@ const allSavedObjects = [
   },
 ];
 
-const $http = () => {};
-$http.post = jest.fn().mockImplementation(() => []);
-const defaultProps = {
-  goInspectObject: () => {},
-  confirmModalPromise: jest.fn(),
-  savedObjectsClient: {
-    find: jest.fn(),
-    bulkGet: jest.fn(),
-  },
-  indexPatterns: {
-    clearCache: jest.fn(),
-  },
-  $http,
-  basePath: '',
-  newIndexPatternUrl: '',
-  kbnIndex: '',
-  services: [],
-  uiCapabilities: {
-    savedObjectsManagement: {
-      read: true,
-      edit: false,
-      delete: false,
-    },
-  },
-  canDelete: true,
-};
-
-beforeEach(() => {
-  findObjects.mockImplementation(() => ({
-    total: 4,
-    savedObjects: [
-      {
-        id: '1',
-        type: 'index-pattern',
-        meta: {
-          title: `MyIndexPattern*`,
-          icon: 'indexPatternApp',
-          editUrl: '#/management/kibana/index_patterns/1',
-          inAppUrl: {
-            path: '/management/kibana/index_patterns/1',
-            uiCapabilitiesPath: 'management.kibana.index_patterns',
+describe('SavedObjectsTable', () => {
+  let defaultProps: SavedObjectsTableProps;
+  let http: ReturnType<typeof httpServiceMock.createStartContract>;
+  let overlays: ReturnType<typeof overlayServiceMock.createStartContract>;
+  let notifications: ReturnType<typeof notificationServiceMock.createStartContract>;
+  let savedObjects: ReturnType<typeof savedObjectsServiceMock.createStartContract>;
+
+  const shallowRender = (overrides: Partial<SavedObjectsTableProps> = {}) => {
+    return (shallowWithI18nProvider(
+      <SavedObjectsTable {...defaultProps} {...overrides} />
+    ) as unknown) as ShallowWrapper<
+      SavedObjectsTableProps,
+      SavedObjectsTableState,
+      SavedObjectsTable
+    >;
+  };
+
+  beforeEach(() => {
+    extractExportDetailsMock.mockReset();
+
+    http = httpServiceMock.createStartContract();
+    overlays = overlayServiceMock.createStartContract();
+    notifications = notificationServiceMock.createStartContract();
+    savedObjects = savedObjectsServiceMock.createStartContract();
+
+    const applications = applicationServiceMock.createStartContract();
+    applications.capabilities = {
+      navLinks: {},
+      management: {},
+      catalogue: {},
+      savedObjectsManagement: {
+        read: true,
+        edit: false,
+        delete: false,
+      },
+    };
+
+    http.post.mockResolvedValue([]);
+
+    getSavedObjectCountsMock.mockReturnValue({
+      'index-pattern': 0,
+      visualization: 0,
+      dashboard: 0,
+      search: 0,
+    });
+
+    defaultProps = {
+      allowedTypes,
+      serviceRegistry: serviceRegistryMock.create(),
+      actionRegistry: actionServiceMock.createStart(),
+      savedObjectsClient: savedObjects.client,
+      indexPatterns: dataPluginMock.createStartContract().indexPatterns,
+      http,
+      overlays,
+      notifications,
+      applications,
+      perPageConfig: 15,
+      goInspectObject: () => {},
+      canGoInApp: () => true,
+    };
+
+    findObjectsMock.mockImplementation(() => ({
+      total: 4,
+      savedObjects: [
+        {
+          id: '1',
+          type: 'index-pattern',
+          meta: {
+            title: `MyIndexPattern*`,
+            icon: 'indexPatternApp',
+            editUrl: '#/management/kibana/index_patterns/1',
+            inAppUrl: {
+              path: '/management/kibana/index_patterns/1',
+              uiCapabilitiesPath: 'management.kibana.index_patterns',
+            },
           },
         },
-      },
-      {
-        id: '2',
-        type: 'search',
-        meta: {
-          title: `MySearch`,
-          icon: 'search',
-          editUrl: '#/management/kibana/objects/savedSearches/2',
-          inAppUrl: {
-            path: '/discover/2',
-            uiCapabilitiesPath: 'discover.show',
+        {
+          id: '2',
+          type: 'search',
+          meta: {
+            title: `MySearch`,
+            icon: 'search',
+            editUrl: '#/management/kibana/objects/savedSearches/2',
+            inAppUrl: {
+              path: '/discover/2',
+              uiCapabilitiesPath: 'discover.show',
+            },
           },
         },
-      },
-      {
-        id: '3',
-        type: 'dashboard',
-        meta: {
-          title: `MyDashboard`,
-          icon: 'dashboardApp',
-          editUrl: '#/management/kibana/objects/savedDashboards/3',
-          inAppUrl: {
-            path: '/dashboard/3',
-            uiCapabilitiesPath: 'dashboard.show',
+        {
+          id: '3',
+          type: 'dashboard',
+          meta: {
+            title: `MyDashboard`,
+            icon: 'dashboardApp',
+            editUrl: '#/management/kibana/objects/savedDashboards/3',
+            inAppUrl: {
+              path: '/dashboard/3',
+              uiCapabilitiesPath: 'dashboard.show',
+            },
           },
         },
-      },
-      {
-        id: '4',
-        type: 'visualization',
-        meta: {
-          title: `MyViz`,
-          icon: 'visualizeApp',
-          editUrl: '#/management/kibana/objects/savedVisualizations/4',
-          inAppUrl: {
-            path: '/visualize/edit/4',
-            uiCapabilitiesPath: 'visualize.show',
+        {
+          id: '4',
+          type: 'visualization',
+          meta: {
+            title: `MyViz`,
+            icon: 'visualizeApp',
+            editUrl: '#/management/kibana/objects/savedVisualizations/4',
+            inAppUrl: {
+              path: '/visualize/edit/4',
+              uiCapabilitiesPath: 'visualize.show',
+            },
           },
         },
-      },
-    ],
-  }));
-});
-
-let addDangerMock;
-let addSuccessMock;
-let addWarningMock;
-
-describe('ObjectsTable', () => {
-  beforeEach(() => {
-    defaultProps.savedObjectsClient.find.mockClear();
-    extractExportDetails.mockReset();
-    // mock _.debounce to fire immediately with no internal timer
-    require('lodash').debounce = func => {
-      function debounced(...args) {
-        return func.apply(this, args);
-      }
-      return debounced;
-    };
-    addDangerMock = jest.fn();
-    addSuccessMock = jest.fn();
-    addWarningMock = jest.fn();
-    require('ui/notify').toastNotifications = {
-      addDanger: addDangerMock,
-      addSuccess: addSuccessMock,
-      addWarning: addWarningMock,
-    };
+      ],
+    }));
   });
 
   it('should render normally', async () => {
-    const component = shallowWithI18nProvider(
-      <ObjectsTable {...defaultProps} perPageConfig={15} />
-    );
+    const component = shallowRender({ perPageConfig: 15 });
 
     // Ensure all promises resolve
     await new Promise(resolve => process.nextTick(resolve));
@@ -238,19 +214,17 @@ describe('ObjectsTable', () => {
   });
 
   it('should add danger toast when find fails', async () => {
-    findObjects.mockImplementation(() => {
+    findObjectsMock.mockImplementation(() => {
       throw new Error('Simulated find error');
     });
-    const component = shallowWithI18nProvider(
-      <ObjectsTable {...defaultProps} perPageConfig={15} />
-    );
+    const component = shallowRender({ perPageConfig: 15 });
 
     // Ensure all promises resolve
     await new Promise(resolve => process.nextTick(resolve));
     // Ensure the state changes are reflected
     component.update();
 
-    expect(addDangerMock).toHaveBeenCalled();
+    expect(notifications.toasts.addDanger).toHaveBeenCalled();
   });
 
   describe('export', () => {
@@ -258,7 +232,7 @@ describe('ObjectsTable', () => {
       const mockSelectedSavedObjects = [
         { id: '1', type: 'index-pattern' },
         { id: '3', type: 'dashboard' },
-      ];
+      ] as SavedObjectWithMetadata[];
 
       const mockSavedObjects = mockSelectedSavedObjects.map(obj => ({
         _id: obj.id,
@@ -272,11 +246,7 @@ describe('ObjectsTable', () => {
         })),
       };
 
-      const { fetchExportObjects } = require('../../../lib/fetch_export_objects');
-
-      const component = shallowWithI18nProvider(
-        <ObjectsTable {...defaultProps} savedObjectsClient={mockSavedObjectsClient} />
-      );
+      const component = shallowRender({ savedObjectsClient: mockSavedObjectsClient });
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -288,8 +258,8 @@ describe('ObjectsTable', () => {
 
       await component.instance().onExport(true);
 
-      expect(fetchExportObjects).toHaveBeenCalledWith(mockSelectedSavedObjects, true);
-      expect(addSuccessMock).toHaveBeenCalledWith({
+      expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true);
+      expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
         title: 'Your file is downloading in the background',
       });
     });
@@ -298,7 +268,7 @@ describe('ObjectsTable', () => {
       const mockSelectedSavedObjects = [
         { id: '1', type: 'index-pattern' },
         { id: '3', type: 'dashboard' },
-      ];
+      ] as SavedObjectWithMetadata[];
 
       const mockSavedObjects = mockSelectedSavedObjects.map(obj => ({
         _id: obj.id,
@@ -312,16 +282,13 @@ describe('ObjectsTable', () => {
         })),
       };
 
-      const { fetchExportObjects } = require('../../../lib/fetch_export_objects');
-      extractExportDetails.mockImplementation(() => ({
+      extractExportDetailsMock.mockImplementation(() => ({
         exportedCount: 2,
         missingRefCount: 1,
         missingReferences: [{ id: '7', type: 'visualisation' }],
       }));
 
-      const component = shallowWithI18nProvider(
-        <ObjectsTable {...defaultProps} savedObjectsClient={mockSavedObjectsClient} />
-      );
+      const component = shallowRender({ savedObjectsClient: mockSavedObjectsClient });
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -333,8 +300,8 @@ describe('ObjectsTable', () => {
 
       await component.instance().onExport(true);
 
-      expect(fetchExportObjects).toHaveBeenCalledWith(mockSelectedSavedObjects, true);
-      expect(addWarningMock).toHaveBeenCalledWith({
+      expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true);
+      expect(notifications.toasts.addWarning).toHaveBeenCalledWith({
         title:
           'Your file is downloading in the background. ' +
           'Some related objects could not be found. ' +
@@ -343,25 +310,21 @@ describe('ObjectsTable', () => {
     });
 
     it('should allow the user to choose when exporting all', async () => {
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
       // Ensure the state changes are reflected
       component.update();
 
-      component.find('Header').prop('onExportAll')();
+      (component.find('Header') as any).prop('onExportAll')();
       component.update();
 
       expect(component.find('EuiModal')).toMatchSnapshot();
     });
 
     it('should export all', async () => {
-      const {
-        fetchExportByTypeAndSearch,
-      } = require('../../../lib/fetch_export_by_type_and_search');
-      const { saveAs } = require('@elastic/filesaver');
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -370,23 +333,24 @@ describe('ObjectsTable', () => {
 
       // Set up mocks
       const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' });
-      fetchExportByTypeAndSearch.mockImplementation(() => blob);
+      fetchExportByTypeAndSearchMock.mockImplementation(() => blob);
 
       await component.instance().onExportAll();
 
-      expect(fetchExportByTypeAndSearch).toHaveBeenCalledWith(POSSIBLE_TYPES, undefined, true);
-      expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson');
-      expect(addSuccessMock).toHaveBeenCalledWith({
+      expect(fetchExportByTypeAndSearchMock).toHaveBeenCalledWith(
+        http,
+        allowedTypes,
+        undefined,
+        true
+      );
+      expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
+      expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
         title: 'Your file is downloading in the background',
       });
     });
 
     it('should export all, accounting for the current search criteria', async () => {
-      const {
-        fetchExportByTypeAndSearch,
-      } = require('../../../lib/fetch_export_by_type_and_search');
-      const { saveAs } = require('@elastic/filesaver');
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       component.instance().onQueryChange({
         query: Query.parse('test'),
@@ -399,13 +363,18 @@ describe('ObjectsTable', () => {
 
       // Set up mocks
       const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' });
-      fetchExportByTypeAndSearch.mockImplementation(() => blob);
+      fetchExportByTypeAndSearchMock.mockImplementation(() => blob);
 
       await component.instance().onExportAll();
 
-      expect(fetchExportByTypeAndSearch).toHaveBeenCalledWith(POSSIBLE_TYPES, 'test*', true);
-      expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson');
-      expect(addSuccessMock).toHaveBeenCalledWith({
+      expect(fetchExportByTypeAndSearchMock).toHaveBeenCalledWith(
+        http,
+        allowedTypes,
+        'test*',
+        true
+      );
+      expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
+      expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
         title: 'Your file is downloading in the background',
       });
     });
@@ -413,7 +382,7 @@ describe('ObjectsTable', () => {
 
   describe('import', () => {
     it('should show the flyout', async () => {
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -427,7 +396,7 @@ describe('ObjectsTable', () => {
     });
 
     it('should hide the flyout', async () => {
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -443,9 +412,7 @@ describe('ObjectsTable', () => {
 
   describe('relationships', () => {
     it('should fetch relationships', async () => {
-      const { getRelationships } = require('../../../lib/get_relationships');
-
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -454,17 +421,11 @@ describe('ObjectsTable', () => {
 
       await component.instance().getRelationships('search', '1');
       const savedObjectTypes = ['index-pattern', 'visualization', 'dashboard', 'search'];
-      expect(getRelationships).toHaveBeenCalledWith(
-        'search',
-        '1',
-        savedObjectTypes,
-        defaultProps.$http,
-        defaultProps.basePath
-      );
+      expect(getRelationshipsMock).toHaveBeenCalledWith(http, 'search', '1', savedObjectTypes);
     });
 
     it('should show the flyout', async () => {
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -483,7 +444,7 @@ describe('ObjectsTable', () => {
             uiCapabilitiesPath: 'discover.show',
           },
         },
-      });
+      } as SavedObjectWithMetadata);
       component.update();
 
       expect(component.find(Relationships)).toMatchSnapshot();
@@ -503,7 +464,7 @@ describe('ObjectsTable', () => {
     });
 
     it('should hide the flyout', async () => {
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -522,12 +483,12 @@ describe('ObjectsTable', () => {
 
   describe('delete', () => {
     it('should show a confirm modal', async () => {
-      const component = shallowWithI18nProvider(<ObjectsTable {...defaultProps} />);
+      const component = shallowRender();
 
       const mockSelectedSavedObjects = [
-        { id: '1', type: 'index-pattern', title: 'Title 1' },
-        { id: '3', type: 'dashboard', title: 'Title 2' },
-      ];
+        { id: '1', type: 'index-pattern' },
+        { id: '3', type: 'dashboard' },
+      ] as SavedObjectWithMetadata[];
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
@@ -546,7 +507,7 @@ describe('ObjectsTable', () => {
       const mockSelectedSavedObjects = [
         { id: '1', type: 'index-pattern' },
         { id: '3', type: 'dashboard' },
-      ];
+      ] as SavedObjectWithMetadata[];
 
       const mockSavedObjects = mockSelectedSavedObjects.map(obj => ({
         id: obj.id,
@@ -562,9 +523,7 @@ describe('ObjectsTable', () => {
         delete: jest.fn(),
       };
 
-      const component = shallowWithI18nProvider(
-        <ObjectsTable {...defaultProps} savedObjectsClient={mockSavedObjectsClient} />
-      );
+      const component = shallowRender({ savedObjectsClient: mockSavedObjectsClient });
 
       // Ensure all promises resolve
       await new Promise(resolve => process.nextTick(resolve));
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
similarity index 73%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js
rename to src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
index 188762f165b24..c76fea5a0fb29 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
@@ -17,17 +17,10 @@
  * under the License.
  */
 
-import chrome from 'ui/chrome';
-import { saveAs } from '@elastic/filesaver';
 import React, { Component } from 'react';
-import PropTypes from 'prop-types';
 import { debounce } from 'lodash';
-import { Header } from './components/header';
-import { Flyout } from './components/flyout';
-import { Relationships } from './components/relationships';
-import { Table } from './components/table';
-import { toastNotifications } from 'ui/notify';
-
+// @ts-ignore
+import { saveAs } from '@elastic/filesaver';
 import {
   EuiSpacer,
   Query,
@@ -54,7 +47,15 @@ import {
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-
+import {
+  SavedObjectsClientContract,
+  SavedObjectsFindOptions,
+  HttpStart,
+  OverlayStart,
+  NotificationsStart,
+  ApplicationStart,
+} from 'src/core/public';
+import { IndexPatternsContract } from '../../../../data/public';
 import {
   parseQuery,
   getSavedObjectCounts,
@@ -63,39 +64,72 @@ import {
   fetchExportObjects,
   fetchExportByTypeAndSearch,
   findObjects,
+  extractExportDetails,
+  SavedObjectsExportResultDetails,
 } from '../../lib';
-import { extractExportDetails } from '../../lib/extract_export_details';
-
-export const POSSIBLE_TYPES = chrome.getInjected('importAndExportableTypes');
-
-export class ObjectsTable extends Component {
-  static propTypes = {
-    savedObjectsClient: PropTypes.object.isRequired,
-    indexPatterns: PropTypes.object.isRequired,
-    $http: PropTypes.func.isRequired,
-    basePath: PropTypes.string.isRequired,
-    perPageConfig: PropTypes.number,
-    newIndexPatternUrl: PropTypes.string.isRequired,
-    confirmModalPromise: PropTypes.func.isRequired,
-    services: PropTypes.array.isRequired,
-    uiCapabilities: PropTypes.object.isRequired,
-    goInspectObject: PropTypes.func.isRequired,
-    canGoInApp: PropTypes.func.isRequired,
-  };
+import { SavedObjectWithMetadata } from '../../types';
+import {
+  ISavedObjectsManagementServiceRegistry,
+  SavedObjectsManagementActionServiceStart,
+} from '../../services';
+import { Header, Table, Flyout, Relationships } from './components';
+
+interface ExportAllOption {
+  id: string;
+  label: string;
+}
 
-  constructor(props) {
+export interface SavedObjectsTableProps {
+  allowedTypes: string[];
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
+  actionRegistry: SavedObjectsManagementActionServiceStart;
+  savedObjectsClient: SavedObjectsClientContract;
+  indexPatterns: IndexPatternsContract;
+  http: HttpStart;
+  overlays: OverlayStart;
+  notifications: NotificationsStart;
+  applications: ApplicationStart;
+  perPageConfig: number;
+  goInspectObject: (obj: SavedObjectWithMetadata) => void;
+  canGoInApp: (obj: SavedObjectWithMetadata) => boolean;
+}
+
+export interface SavedObjectsTableState {
+  totalCount: number;
+  page: number;
+  perPage: number;
+  savedObjects: SavedObjectWithMetadata[];
+  savedObjectCounts: Record<string, number>;
+  activeQuery: Query;
+  selectedSavedObjects: SavedObjectWithMetadata[];
+  isShowingImportFlyout: boolean;
+  isSearching: boolean;
+  filteredItemCount: number;
+  isShowingRelationships: boolean;
+  relationshipObject?: SavedObjectWithMetadata;
+  isShowingDeleteConfirmModal: boolean;
+  isShowingExportAllOptionsModal: boolean;
+  isDeleting: boolean;
+  exportAllOptions: ExportAllOption[];
+  exportAllSelectedOptions: Record<string, boolean>;
+  isIncludeReferencesDeepChecked: boolean;
+}
+
+export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedObjectsTableState> {
+  private _isMounted = false;
+
+  constructor(props: SavedObjectsTableProps) {
     super(props);
-    this.savedObjectTypes = POSSIBLE_TYPES;
 
     this.state = {
       totalCount: 0,
       page: 0,
       perPage: props.perPageConfig || 50,
       savedObjects: [],
-      savedObjectCounts: this.savedObjectTypes.reduce((typeToCountMap, type) => {
+      savedObjectCounts: props.allowedTypes.reduce((typeToCountMap, type) => {
         typeToCountMap[type] = 0;
         return typeToCountMap;
-      }, {}),
+      }, {} as Record<string, number>),
       activeQuery: Query.parse(''),
       selectedSavedObjects: [],
       isShowingImportFlyout: false,
@@ -124,21 +158,20 @@ export class ObjectsTable extends Component {
   }
 
   fetchCounts = async () => {
+    const { allowedTypes } = this.props;
     const { queryText, visibleTypes } = parseQuery(this.state.activeQuery);
 
-    const filteredTypes = this.savedObjectTypes.filter(
-      type => !visibleTypes || visibleTypes.includes(type)
-    );
+    const filteredTypes = allowedTypes.filter(type => !visibleTypes || visibleTypes.includes(type));
 
     // These are the saved objects visible in the table.
     const filteredSavedObjectCounts = await getSavedObjectCounts(
-      this.props.$http,
+      this.props.http,
       filteredTypes,
       queryText
     );
 
-    const exportAllOptions = [];
-    const exportAllSelectedOptions = {};
+    const exportAllOptions: ExportAllOption[] = [];
+    const exportAllSelectedOptions: Record<string, boolean> = {};
 
     Object.keys(filteredSavedObjectCounts).forEach(id => {
       // Add this type as a bulk-export option.
@@ -147,17 +180,13 @@ export class ObjectsTable extends Component {
         label: `${id} (${filteredSavedObjectCounts[id] || 0})`,
       });
 
-      // Select it by defayult.
+      // Select it by default.
       exportAllSelectedOptions[id] = true;
     });
 
     // Fetch all the saved objects that exist so we can accurately populate the counts within
     // the table filter dropdown.
-    const savedObjectCounts = await getSavedObjectCounts(
-      this.props.$http,
-      this.savedObjectTypes,
-      queryText
-    );
+    const savedObjectCounts = await getSavedObjectCounts(this.props.http, allowedTypes, queryText);
 
     this.setState(state => ({
       ...state,
@@ -178,66 +207,64 @@ export class ObjectsTable extends Component {
 
   debouncedFetch = debounce(async () => {
     const { activeQuery: query, page, perPage } = this.state;
+    const { notifications, http, allowedTypes } = this.props;
     const { queryText, visibleTypes } = parseQuery(query);
     // "searchFields" is missing from the "findOptions" but gets injected via the API.
     // The API extracts the fields from each uiExports.savedObjectsManagement "defaultSearchField" attribute
-    const findOptions = {
+    const findOptions: SavedObjectsFindOptions = {
       search: queryText ? `${queryText}*` : undefined,
       perPage,
       page: page + 1,
       fields: ['id'],
-      type: this.savedObjectTypes.filter(type => !visibleTypes || visibleTypes.includes(type)),
+      type: allowedTypes.filter(type => !visibleTypes || visibleTypes.includes(type)),
     };
     if (findOptions.type.length > 1) {
       findOptions.sortField = 'type';
     }
 
-    let resp;
     try {
-      resp = await findObjects(findOptions);
+      const resp = await findObjects(http, findOptions);
+      if (!this._isMounted) {
+        return;
+      }
+
+      this.setState(({ activeQuery }) => {
+        // ignore results for old requests
+        if (activeQuery.text !== query.text) {
+          return null;
+        }
+
+        return {
+          savedObjects: resp.savedObjects,
+          filteredItemCount: resp.total,
+          isSearching: false,
+        };
+      });
     } catch (error) {
       if (this._isMounted) {
         this.setState({
           isSearching: false,
         });
       }
-      toastNotifications.addDanger({
+      notifications.toasts.addDanger({
         title: i18n.translate(
-          'kbn.management.objects.objectsTable.unableFindSavedObjectsNotificationMessage',
+          'savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage',
           { defaultMessage: 'Unable find saved objects' }
         ),
         text: `${error}`,
       });
-      return;
-    }
-
-    if (!this._isMounted) {
-      return;
     }
-
-    this.setState(({ activeQuery }) => {
-      // ignore results for old requests
-      if (activeQuery.text !== query.text) {
-        return {};
-      }
-
-      return {
-        savedObjects: resp.savedObjects,
-        filteredItemCount: resp.total,
-        isSearching: false,
-      };
-    });
   }, 300);
 
   refreshData = async () => {
     await Promise.all([this.fetchSavedObjects(), this.fetchCounts()]);
   };
 
-  onSelectionChanged = selection => {
+  onSelectionChanged = (selection: SavedObjectWithMetadata[]) => {
     this.setState({ selectedSavedObjects: selection });
   };
 
-  onQueryChange = ({ query }) => {
+  onQueryChange = ({ query }: { query: Query }) => {
     // TODO: Use isSameQuery to compare new query with state.activeQuery to avoid re-fetching the
     // same data we already have.
     this.setState(
@@ -253,7 +280,7 @@ export class ObjectsTable extends Component {
     );
   };
 
-  onTableChange = async table => {
+  onTableChange = async (table: any) => {
     const { index: page, size: perPage } = table.page || {};
 
     this.setState(
@@ -266,7 +293,7 @@ export class ObjectsTable extends Component {
     );
   };
 
-  onShowRelationships = object => {
+  onShowRelationships = (object: SavedObjectWithMetadata) => {
     this.setState({
       isShowingRelationships: true,
       relationshipObject: object,
@@ -280,16 +307,17 @@ export class ObjectsTable extends Component {
     });
   };
 
-  onExport = async includeReferencesDeep => {
+  onExport = async (includeReferencesDeep: boolean) => {
     const { selectedSavedObjects } = this.state;
+    const { notifications, http } = this.props;
     const objectsToExport = selectedSavedObjects.map(obj => ({ id: obj.id, type: obj.type }));
 
     let blob;
     try {
-      blob = await fetchExportObjects(objectsToExport, includeReferencesDeep);
+      blob = await fetchExportObjects(http, objectsToExport, includeReferencesDeep);
     } catch (e) {
-      toastNotifications.addDanger({
-        title: i18n.translate('kbn.management.objects.objectsTable.export.dangerNotification', {
+      notifications.toasts.addDanger({
+        title: i18n.translate('savedObjectsManagement.objectsTable.export.dangerNotification', {
           defaultMessage: 'Unable to generate export',
         }),
       });
@@ -304,24 +332,26 @@ export class ObjectsTable extends Component {
 
   onExportAll = async () => {
     const { exportAllSelectedOptions, isIncludeReferencesDeepChecked, activeQuery } = this.state;
+    const { notifications, http } = this.props;
     const { queryText } = parseQuery(activeQuery);
     const exportTypes = Object.entries(exportAllSelectedOptions).reduce((accum, [id, selected]) => {
       if (selected) {
         accum.push(id);
       }
       return accum;
-    }, []);
+    }, [] as string[]);
 
     let blob;
     try {
       blob = await fetchExportByTypeAndSearch(
+        http,
         exportTypes,
         queryText ? `${queryText}*` : undefined,
         isIncludeReferencesDeepChecked
       );
     } catch (e) {
-      toastNotifications.addDanger({
-        title: i18n.translate('kbn.management.objects.objectsTable.export.dangerNotification', {
+      notifications.toasts.addDanger({
+        title: i18n.translate('savedObjectsManagement.objectsTable.export.dangerNotification', {
           defaultMessage: 'Unable to generate export',
         }),
       });
@@ -335,11 +365,12 @@ export class ObjectsTable extends Component {
     this.setState({ isShowingExportAllOptionsModal: false });
   };
 
-  showExportSuccessMessage = exportDetails => {
+  showExportSuccessMessage = (exportDetails: SavedObjectsExportResultDetails | undefined) => {
+    const { notifications } = this.props;
     if (exportDetails && exportDetails.missingReferences.length > 0) {
-      toastNotifications.addWarning({
+      notifications.toasts.addWarning({
         title: i18n.translate(
-          'kbn.management.objects.objectsTable.export.successWithMissingRefsNotification',
+          'savedObjectsManagement.objectsTable.export.successWithMissingRefsNotification',
           {
             defaultMessage:
               'Your file is downloading in the background. ' +
@@ -349,8 +380,8 @@ export class ObjectsTable extends Component {
         ),
       });
     } else {
-      toastNotifications.addSuccess({
-        title: i18n.translate('kbn.management.objects.objectsTable.export.successNotification', {
+      notifications.toasts.addSuccess({
+        title: i18n.translate('savedObjectsManagement.objectsTable.export.successNotification', {
           defaultMessage: 'Your file is downloading in the background',
         }),
       });
@@ -412,30 +443,30 @@ export class ObjectsTable extends Component {
     });
   };
 
-  getRelationships = async (type, id) => {
-    return await getRelationships(
-      type,
-      id,
-      this.savedObjectTypes,
-      this.props.$http,
-      this.props.basePath
-    );
+  getRelationships = async (type: string, id: string) => {
+    const { allowedTypes, http } = this.props;
+    return await getRelationships(http, type, id, allowedTypes);
   };
 
   renderFlyout() {
     if (!this.state.isShowingImportFlyout) {
       return null;
     }
+    const { applications } = this.props;
+    const newIndexPatternUrl = applications.getUrlForApp('kibana', {
+      path: '#/management/kibana/index_pattern',
+    });
 
     return (
       <Flyout
         close={this.hideImportFlyout}
         done={this.finishImport}
-        services={this.props.services}
+        http={this.props.http}
+        serviceRegistry={this.props.serviceRegistry}
         indexPatterns={this.props.indexPatterns}
-        newIndexPatternUrl={this.props.newIndexPatternUrl}
-        savedObjectTypes={this.props.savedObjectTypes}
-        confirmModalPromise={this.props.confirmModalPromise}
+        newIndexPatternUrl={newIndexPatternUrl}
+        allowedTypes={this.props.allowedTypes}
+        overlays={this.props.overlays}
       />
     );
   }
@@ -447,10 +478,10 @@ export class ObjectsTable extends Component {
 
     return (
       <Relationships
-        savedObject={this.state.relationshipObject}
+        basePath={this.props.http.basePath}
+        savedObject={this.state.relationshipObject!}
         getRelationships={this.getRelationships}
         close={this.onHideRelationships}
-        getDashboardUrl={this.props.getDashboardUrl}
         goInspectObject={this.props.goInspectObject}
         canGoInApp={this.props.canGoInApp}
       />
@@ -482,7 +513,7 @@ export class ObjectsTable extends Component {
         <EuiConfirmModal
           title={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModalTitle"
+              id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModalTitle"
               defaultMessage="Delete saved objects"
             />
           }
@@ -491,19 +522,19 @@ export class ObjectsTable extends Component {
           buttonColor="danger"
           cancelButtonText={
             <FormattedMessage
-              id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
+              id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
               defaultMessage="Cancel"
             />
           }
           confirmButtonText={
             isDeleting ? (
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel"
+                id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel"
                 defaultMessage="Deleting…"
               />
             ) : (
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
+                id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
                 defaultMessage="Delete"
               />
             )
@@ -512,7 +543,7 @@ export class ObjectsTable extends Component {
         >
           <p>
             <FormattedMessage
-              id="kbn.management.objects.deleteSavedObjectsConfirmModalDescription"
+              id="savedObjectsManagement.deleteSavedObjectsConfirmModalDescription"
               defaultMessage="This action will delete the following saved objects:"
             />
           </p>
@@ -522,7 +553,7 @@ export class ObjectsTable extends Component {
               {
                 field: 'type',
                 name: i18n.translate(
-                  'kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName',
+                  'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName',
                   { defaultMessage: 'Type' }
                 ),
                 width: '50px',
@@ -535,14 +566,14 @@ export class ObjectsTable extends Component {
               {
                 field: 'id',
                 name: i18n.translate(
-                  'kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.idColumnName',
+                  'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName',
                   { defaultMessage: 'Id' }
                 ),
               },
               {
                 field: 'meta.title',
                 name: i18n.translate(
-                  'kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName',
+                  'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName',
                   { defaultMessage: 'Title' }
                 ),
               },
@@ -586,7 +617,7 @@ export class ObjectsTable extends Component {
           <EuiModalHeader>
             <EuiModalHeaderTitle>
               <FormattedMessage
-                id="kbn.management.objects.objectsTable.exportObjectsConfirmModalTitle"
+                id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle"
                 defaultMessage="Export {filteredItemCount, plural, one{# object} other {# objects}}"
                 values={{
                   filteredItemCount,
@@ -598,7 +629,7 @@ export class ObjectsTable extends Component {
             <EuiFormRow
               label={
                 <FormattedMessage
-                  id="kbn.management.objects.objectsTable.exportObjectsConfirmModalDescription"
+                  id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription"
                   defaultMessage="Select which types to export"
                 />
               }
@@ -626,7 +657,7 @@ export class ObjectsTable extends Component {
               name="includeReferencesDeep"
               label={
                 <FormattedMessage
-                  id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
+                  id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
                   defaultMessage="Include related objects"
                 />
               }
@@ -641,7 +672,7 @@ export class ObjectsTable extends Component {
                   <EuiFlexItem grow={false}>
                     <EuiButtonEmpty onClick={this.closeExportAllModal}>
                       <FormattedMessage
-                        id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
+                        id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
                         defaultMessage="Cancel"
                       />
                     </EuiButtonEmpty>
@@ -649,7 +680,7 @@ export class ObjectsTable extends Component {
                   <EuiFlexItem grow={false}>
                     <EuiButton fill onClick={this.onExportAll}>
                       <FormattedMessage
-                        id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
+                        id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
                         defaultMessage="Export all"
                       />
                     </EuiButton>
@@ -673,12 +704,13 @@ export class ObjectsTable extends Component {
       isSearching,
       savedObjectCounts,
     } = this.state;
+    const { http, allowedTypes, applications } = this.props;
 
     const selectionConfig = {
       onSelectionChange: this.onSelectionChanged,
     };
 
-    const filterOptions = this.savedObjectTypes.map(type => ({
+    const filterOptions = allowedTypes.map(type => ({
       value: type,
       name: type,
       view: `${type} (${savedObjectCounts[type] || 0})`,
@@ -698,14 +730,16 @@ export class ObjectsTable extends Component {
         />
         <EuiSpacer size="xs" />
         <Table
+          basePath={http.basePath}
           itemId={'id'}
+          actionRegistry={this.props.actionRegistry}
           selectionConfig={selectionConfig}
           selectedSavedObjects={selectedSavedObjects}
           onQueryChange={this.onQueryChange}
           onTableChange={this.onTableChange}
           filterOptions={filterOptions}
           onExport={this.onExport}
-          canDelete={this.props.uiCapabilities.savedObjectsManagement.delete}
+          canDelete={applications.capabilities.savedObjectsManagement.delete as boolean}
           onDelete={this.onDelete}
           goInspectObject={this.props.goInspectObject}
           pageIndex={page}
diff --git a/src/plugins/saved_objects_management/public/management_section/types.ts b/src/plugins/saved_objects_management/public/management_section/types.ts
new file mode 100644
index 0000000000000..541746534b84a
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/management_section/types.ts
@@ -0,0 +1,38 @@
+/*
+ * 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 { SavedObjectReference } from '../../../../core/types';
+
+export interface ObjectField {
+  type: FieldType;
+  name: string;
+  value: any;
+}
+
+export type FieldType = 'text' | 'number' | 'boolean' | 'array' | 'json';
+
+export interface FieldState {
+  value?: any;
+  invalid?: boolean;
+}
+
+export interface SubmittedFormData {
+  attributes: any;
+  references: SavedObjectReference[];
+}
diff --git a/src/plugins/saved_objects_management/public/mocks.ts b/src/plugins/saved_objects_management/public/mocks.ts
index 8cf23afe87907..1de3de8e85302 100644
--- a/src/plugins/saved_objects_management/public/mocks.ts
+++ b/src/plugins/saved_objects_management/public/mocks.ts
@@ -17,23 +17,27 @@
  * under the License.
  */
 
-import { actionRegistryMock } from './services/action_registry.mock';
+import { actionServiceMock } from './services/action_service.mock';
+import { serviceRegistryMock } from './services/service_registry.mock';
 import { SavedObjectsManagementPluginSetup, SavedObjectsManagementPluginStart } from './plugin';
 
 const createSetupContractMock = (): jest.Mocked<SavedObjectsManagementPluginSetup> => {
   const mock = {
-    actionRegistry: actionRegistryMock.create(),
+    actions: actionServiceMock.createSetup(),
+    serviceRegistry: serviceRegistryMock.create(),
   };
   return mock;
 };
 
 const createStartContractMock = (): jest.Mocked<SavedObjectsManagementPluginStart> => {
-  const mock = {};
+  const mock = {
+    actions: actionServiceMock.createStart(),
+  };
   return mock;
 };
 
 export const savedObjectsManagementPluginMock = {
-  createActionRegistry: actionRegistryMock.create,
+  createServiceRegistry: serviceRegistryMock.create,
   createSetupContract: createSetupContractMock,
   createStartContract: createStartContractMock,
 };
diff --git a/src/plugins/saved_objects_management/public/plugin.test.ts b/src/plugins/saved_objects_management/public/plugin.test.ts
index 1cafbb235ad5b..09080f46a6869 100644
--- a/src/plugins/saved_objects_management/public/plugin.test.ts
+++ b/src/plugins/saved_objects_management/public/plugin.test.ts
@@ -20,6 +20,9 @@
 import { coreMock } from '../../../core/public/mocks';
 // eslint-disable-next-line @kbn/eslint/no-restricted-paths
 import { homePluginMock } from '../../home/public/mocks';
+// eslint-disable-next-line @kbn/eslint/no-restricted-paths
+import { managementPluginMock } from '../../management/public/mocks';
+import { dataPluginMock } from '../../data/public/mocks';
 import { SavedObjectsManagementPlugin } from './plugin';
 
 describe('SavedObjectsManagementPlugin', () => {
@@ -31,10 +34,13 @@ describe('SavedObjectsManagementPlugin', () => {
 
   describe('#setup', () => {
     it('registers the saved_objects feature to the home plugin', async () => {
-      const coreSetup = coreMock.createSetup();
+      const coreSetup = coreMock.createSetup({
+        pluginStartDeps: { data: dataPluginMock.createStartContract() },
+      });
       const homeSetup = homePluginMock.createSetupContract();
+      const managementSetup = managementPluginMock.createSetupContract();
 
-      await plugin.setup(coreSetup, { home: homeSetup });
+      await plugin.setup(coreSetup, { home: homeSetup, management: managementSetup });
 
       expect(homeSetup.featureCatalogue.register).toHaveBeenCalledTimes(1);
       expect(homeSetup.featureCatalogue.register).toHaveBeenCalledWith(
diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts
index 3f2e9c166058e..c8dede3da9263 100644
--- a/src/plugins/saved_objects_management/public/plugin.ts
+++ b/src/plugins/saved_objects_management/public/plugin.ts
@@ -19,37 +19,59 @@
 
 import { i18n } from '@kbn/i18n';
 import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
+import { ManagementSetup } from '../../management/public';
+import { DataPublicPluginStart } from '../../data/public';
+import { DashboardStart } from '../../dashboard/public';
+import { DiscoverStart } from '../../discover/public';
 import { HomePublicPluginSetup, FeatureCatalogueCategory } from '../../home/public';
+import { VisualizationsStart } from '../../visualizations/public';
 import {
-  SavedObjectsManagementActionRegistry,
-  ISavedObjectsManagementActionRegistry,
+  SavedObjectsManagementActionService,
+  SavedObjectsManagementActionServiceSetup,
+  SavedObjectsManagementActionServiceStart,
+  SavedObjectsManagementServiceRegistry,
+  ISavedObjectsManagementServiceRegistry,
 } from './services';
+import { registerServices } from './register_services';
 
 export interface SavedObjectsManagementPluginSetup {
-  actionRegistry: ISavedObjectsManagementActionRegistry;
+  actions: SavedObjectsManagementActionServiceSetup;
+  serviceRegistry: ISavedObjectsManagementServiceRegistry;
 }
 
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-export interface SavedObjectsManagementPluginStart {}
+export interface SavedObjectsManagementPluginStart {
+  actions: SavedObjectsManagementActionServiceStart;
+}
 
 export interface SetupDependencies {
+  management: ManagementSetup;
   home: HomePublicPluginSetup;
 }
 
+export interface StartDependencies {
+  data: DataPublicPluginStart;
+  dashboard?: DashboardStart;
+  visualizations?: VisualizationsStart;
+  discover?: DiscoverStart;
+}
+
 export class SavedObjectsManagementPlugin
   implements
     Plugin<
       SavedObjectsManagementPluginSetup,
       SavedObjectsManagementPluginStart,
       SetupDependencies,
-      {}
+      StartDependencies
     > {
-  private actionRegistry = new SavedObjectsManagementActionRegistry();
+  private actionService = new SavedObjectsManagementActionService();
+  private serviceRegistry = new SavedObjectsManagementServiceRegistry();
 
   public setup(
-    core: CoreSetup<{}>,
-    { home }: SetupDependencies
+    core: CoreSetup<StartDependencies, SavedObjectsManagementPluginStart>,
+    { home, management }: SetupDependencies
   ): SavedObjectsManagementPluginSetup {
+    const actionSetup = this.actionService.setup();
+
     home.featureCatalogue.register({
       id: 'saved_objects',
       title: i18n.translate('savedObjectsManagement.objects.savedObjectsTitle', {
@@ -65,12 +87,39 @@ export class SavedObjectsManagementPlugin
       category: FeatureCatalogueCategory.ADMIN,
     });
 
+    const kibanaSection = management.sections.getSection('kibana');
+    if (!kibanaSection) {
+      throw new Error('`kibana` management section not found.');
+    }
+    kibanaSection.registerApp({
+      id: 'objects',
+      title: i18n.translate('savedObjectsManagement.managementSectionLabel', {
+        defaultMessage: 'Saved Objects',
+      }),
+      order: 10,
+      mount: async mountParams => {
+        const { mountManagementSection } = await import('./management_section');
+        return mountManagementSection({
+          core,
+          serviceRegistry: this.serviceRegistry,
+          mountParams,
+        });
+      },
+    });
+
+    // depends on `getStartServices`, should not be awaited
+    registerServices(this.serviceRegistry, core.getStartServices);
+
     return {
-      actionRegistry: this.actionRegistry,
+      actions: actionSetup,
+      serviceRegistry: this.serviceRegistry,
     };
   }
 
   public start(core: CoreStart) {
-    return {};
+    const actionStart = this.actionService.start();
+    return {
+      actions: actionStart,
+    };
   }
 }
diff --git a/src/plugins/saved_objects_management/public/register_services.ts b/src/plugins/saved_objects_management/public/register_services.ts
new file mode 100644
index 0000000000000..a34b632b78f6c
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/register_services.ts
@@ -0,0 +1,59 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { StartServicesAccessor } from '../../../core/public';
+import { SavedObjectsManagementPluginStart, StartDependencies } from './plugin';
+import { ISavedObjectsManagementServiceRegistry } from './services';
+
+export const registerServices = async (
+  registry: ISavedObjectsManagementServiceRegistry,
+  getStartServices: StartServicesAccessor<StartDependencies, SavedObjectsManagementPluginStart>
+) => {
+  const [coreStart, { dashboard, data, visualizations, discover }] = await getStartServices();
+
+  if (dashboard) {
+    registry.register({
+      id: 'savedDashboards',
+      title: 'dashboards',
+      service: dashboard.getSavedDashboardLoader(),
+    });
+  }
+
+  if (visualizations) {
+    registry.register({
+      id: 'savedVisualizations',
+      title: 'visualizations',
+      service: visualizations.savedVisualizationsLoader,
+    });
+  }
+
+  if (discover) {
+    registry.register({
+      id: 'savedSearches',
+      title: 'searches',
+      service: discover.savedSearches.createLoader({
+        savedObjectsClient: coreStart.savedObjects.client,
+        indexPatterns: data.indexPatterns,
+        search: data.search,
+        chrome: coreStart.chrome,
+        overlays: coreStart.overlays,
+      }),
+    });
+  }
+};
diff --git a/src/plugins/saved_objects_management/public/services/action_service.mock.ts b/src/plugins/saved_objects_management/public/services/action_service.mock.ts
new file mode 100644
index 0000000000000..97c95a589b925
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/services/action_service.mock.ts
@@ -0,0 +1,57 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {
+  SavedObjectsManagementActionService,
+  SavedObjectsManagementActionServiceSetup,
+  SavedObjectsManagementActionServiceStart,
+} from './action_service';
+
+const createSetupMock = (): jest.Mocked<SavedObjectsManagementActionServiceSetup> => {
+  const mock = {
+    register: jest.fn(),
+  };
+  return mock;
+};
+
+const createStartMock = (): jest.Mocked<SavedObjectsManagementActionServiceStart> => {
+  const mock = {
+    has: jest.fn(),
+    getAll: jest.fn(),
+  };
+
+  mock.has.mockReturnValue(true);
+  mock.getAll.mockReturnValue([]);
+
+  return mock;
+};
+
+const createServiceMock = (): jest.Mocked<PublicMethodsOf<SavedObjectsManagementActionService>> => {
+  const mock = {
+    setup: jest.fn().mockReturnValue(createSetupMock()),
+    start: jest.fn().mockReturnValue(createStartMock()),
+  };
+  return mock;
+};
+
+export const actionServiceMock = {
+  create: createServiceMock,
+  createSetup: createSetupMock,
+  createStart: createStartMock,
+};
diff --git a/src/plugins/saved_objects_management/public/services/action_registry.test.ts b/src/plugins/saved_objects_management/public/services/action_service.test.ts
similarity index 69%
rename from src/plugins/saved_objects_management/public/services/action_registry.test.ts
rename to src/plugins/saved_objects_management/public/services/action_service.test.ts
index eb3bda00f4196..107554589f83d 100644
--- a/src/plugins/saved_objects_management/public/services/action_registry.test.ts
+++ b/src/plugins/saved_objects_management/public/services/action_service.test.ts
@@ -17,8 +17,11 @@
  * under the License.
  */
 
-import { SavedObjectsManagementActionRegistry } from './action_registry';
-import { SavedObjectsManagementAction } from './action_types';
+import {
+  SavedObjectsManagementActionService,
+  SavedObjectsManagementActionServiceSetup,
+} from './action_service';
+import { SavedObjectsManagementAction } from './types';
 
 class DummyAction extends SavedObjectsManagementAction {
   constructor(public id: string) {
@@ -36,27 +39,30 @@ class DummyAction extends SavedObjectsManagementAction {
 }
 
 describe('SavedObjectsManagementActionRegistry', () => {
-  let registry: SavedObjectsManagementActionRegistry;
+  let service: SavedObjectsManagementActionService;
+  let setup: SavedObjectsManagementActionServiceSetup;
 
   const createAction = (id: string): SavedObjectsManagementAction => {
     return new DummyAction(id);
   };
 
   beforeEach(() => {
-    registry = new SavedObjectsManagementActionRegistry();
+    service = new SavedObjectsManagementActionService();
+    setup = service.setup();
   });
 
   describe('#register', () => {
     it('allows actions to be registered and retrieved', () => {
       const action = createAction('foo');
-      registry.register(action);
-      expect(registry.getAll()).toContain(action);
+      setup.register(action);
+      const start = service.start();
+      expect(start.getAll()).toContain(action);
     });
 
     it('does not allow actions with duplicate ids to be registered', () => {
       const action = createAction('my-action');
-      registry.register(action);
-      expect(() => registry.register(action)).toThrowErrorMatchingInlineSnapshot(
+      setup.register(action);
+      expect(() => setup.register(action)).toThrowErrorMatchingInlineSnapshot(
         `"Saved Objects Management Action with id 'my-action' already exists"`
       );
     });
@@ -65,12 +71,14 @@ describe('SavedObjectsManagementActionRegistry', () => {
   describe('#has', () => {
     it('returns true when an action with a matching ID exists', () => {
       const action = createAction('existing-action');
-      registry.register(action);
-      expect(registry.has('existing-action')).toEqual(true);
+      setup.register(action);
+      const start = service.start();
+      expect(start.has('existing-action')).toEqual(true);
     });
 
     it(`returns false when an action doesn't exist`, () => {
-      expect(registry.has('missing-action')).toEqual(false);
+      const start = service.start();
+      expect(start.has('missing-action')).toEqual(false);
     });
   });
 });
diff --git a/src/plugins/saved_objects_management/public/services/action_registry.ts b/src/plugins/saved_objects_management/public/services/action_service.ts
similarity index 56%
rename from src/plugins/saved_objects_management/public/services/action_registry.ts
rename to src/plugins/saved_objects_management/public/services/action_service.ts
index 8bf77231dd73f..2b0b4cf5431e5 100644
--- a/src/plugins/saved_objects_management/public/services/action_registry.ts
+++ b/src/plugins/saved_objects_management/public/services/action_service.ts
@@ -17,36 +17,44 @@
  * under the License.
  */
 
-import { SavedObjectsManagementAction } from './action_types';
-
-export type ISavedObjectsManagementActionRegistry = PublicMethodsOf<
-  SavedObjectsManagementActionRegistry
->;
-
-export class SavedObjectsManagementActionRegistry {
-  private readonly actions = new Map<string, SavedObjectsManagementAction>();
+import { SavedObjectsManagementAction } from './types';
 
+export interface SavedObjectsManagementActionServiceSetup {
   /**
    * register given action in the registry.
    */
-  register(action: SavedObjectsManagementAction) {
-    if (this.actions.has(action.id)) {
-      throw new Error(`Saved Objects Management Action with id '${action.id}' already exists`);
-    }
-    this.actions.set(action.id, action);
-  }
+  register: (action: SavedObjectsManagementAction) => void;
+}
 
+export interface SavedObjectsManagementActionServiceStart {
   /**
    * return true if the registry contains given action, false otherwise.
    */
-  has(actionId: string) {
-    return this.actions.has(actionId);
-  }
-
+  has: (actionId: string) => boolean;
   /**
    * return all {@link SavedObjectsManagementAction | actions} currently registered.
    */
-  getAll() {
-    return [...this.actions.values()];
+  getAll: () => SavedObjectsManagementAction[];
+}
+
+export class SavedObjectsManagementActionService {
+  private readonly actions = new Map<string, SavedObjectsManagementAction>();
+
+  setup(): SavedObjectsManagementActionServiceSetup {
+    return {
+      register: action => {
+        if (this.actions.has(action.id)) {
+          throw new Error(`Saved Objects Management Action with id '${action.id}' already exists`);
+        }
+        this.actions.set(action.id, action);
+      },
+    };
+  }
+
+  start(): SavedObjectsManagementActionServiceStart {
+    return {
+      has: actionId => this.actions.has(actionId),
+      getAll: () => [...this.actions.values()],
+    };
   }
 }
diff --git a/src/plugins/saved_objects_management/public/services/index.ts b/src/plugins/saved_objects_management/public/services/index.ts
index d6353576b8e11..a59ad9012c402 100644
--- a/src/plugins/saved_objects_management/public/services/index.ts
+++ b/src/plugins/saved_objects_management/public/services/index.ts
@@ -18,7 +18,13 @@
  */
 
 export {
-  SavedObjectsManagementActionRegistry,
-  ISavedObjectsManagementActionRegistry,
-} from './action_registry';
-export { SavedObjectsManagementAction, SavedObjectsManagementRecord } from './action_types';
+  SavedObjectsManagementActionService,
+  SavedObjectsManagementActionServiceStart,
+  SavedObjectsManagementActionServiceSetup,
+} from './action_service';
+export {
+  SavedObjectsManagementServiceRegistry,
+  ISavedObjectsManagementServiceRegistry,
+  SavedObjectsManagementServiceRegistryEntry,
+} from './service_registry';
+export { SavedObjectsManagementAction, SavedObjectsManagementRecord } from './types';
diff --git a/src/plugins/saved_objects_management/public/services/action_registry.mock.ts b/src/plugins/saved_objects_management/public/services/service_registry.mock.ts
similarity index 79%
rename from src/plugins/saved_objects_management/public/services/action_registry.mock.ts
rename to src/plugins/saved_objects_management/public/services/service_registry.mock.ts
index a9093ad42d0ac..2e671c781928f 100644
--- a/src/plugins/saved_objects_management/public/services/action_registry.mock.ts
+++ b/src/plugins/saved_objects_management/public/services/service_registry.mock.ts
@@ -17,21 +17,20 @@
  * under the License.
  */
 
-import { ISavedObjectsManagementActionRegistry } from './action_registry';
+import { ISavedObjectsManagementServiceRegistry } from './service_registry';
 
-const createRegistryMock = (): jest.Mocked<ISavedObjectsManagementActionRegistry> => {
+const createRegistryMock = (): jest.Mocked<ISavedObjectsManagementServiceRegistry> => {
   const mock = {
     register: jest.fn(),
-    has: jest.fn(),
-    getAll: jest.fn(),
+    all: jest.fn(),
+    get: jest.fn(),
   };
 
-  mock.has.mockReturnValue(true);
-  mock.getAll.mockReturnValue([]);
+  mock.all.mockReturnValue([]);
 
   return mock;
 };
 
-export const actionRegistryMock = {
+export const serviceRegistryMock = {
   create: createRegistryMock,
 };
diff --git a/src/plugins/saved_objects_management/public/services/service_registry.ts b/src/plugins/saved_objects_management/public/services/service_registry.ts
new file mode 100644
index 0000000000000..2d6ec0b92047a
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/services/service_registry.ts
@@ -0,0 +1,49 @@
+/*
+ * 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 { SavedObjectLoader } from '../../../saved_objects/public';
+
+export interface SavedObjectsManagementServiceRegistryEntry {
+  id: string;
+  service: SavedObjectLoader;
+  title: string;
+}
+
+export type ISavedObjectsManagementServiceRegistry = PublicMethodsOf<
+  SavedObjectsManagementServiceRegistry
+>;
+
+export class SavedObjectsManagementServiceRegistry {
+  private readonly registry = new Map<string, SavedObjectsManagementServiceRegistryEntry>();
+
+  public register(entry: SavedObjectsManagementServiceRegistryEntry) {
+    if (this.registry.has(entry.id)) {
+      throw new Error('');
+    }
+    this.registry.set(entry.id, entry);
+  }
+
+  public all(): SavedObjectsManagementServiceRegistryEntry[] {
+    return [...this.registry.values()];
+  }
+
+  public get(id: string): SavedObjectsManagementServiceRegistryEntry | undefined {
+    return this.registry.get(id);
+  }
+}
diff --git a/src/plugins/saved_objects_management/public/services/action_types.ts b/src/plugins/saved_objects_management/public/services/types.ts
similarity index 100%
rename from src/plugins/saved_objects_management/public/services/action_types.ts
rename to src/plugins/saved_objects_management/public/services/types.ts
diff --git a/src/plugins/saved_objects_management/public/types.ts b/src/plugins/saved_objects_management/public/types.ts
new file mode 100644
index 0000000000000..e91b5d253b55f
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/types.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export { SavedObjectMetadata, SavedObjectWithMetadata, SavedObjectRelation } from '../common';
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/index.js b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts
similarity index 61%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/index.js
rename to src/plugins/saved_objects_management/server/routes/get_allowed_types.ts
index 3965c42ac088d..ab5bec6678946 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/index.js
+++ b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts
@@ -17,20 +17,24 @@
  * under the License.
  */
 
-import { i18n } from '@kbn/i18n';
-import { management } from 'ui/management';
-import './_view';
-import './_objects';
-import 'ace';
-import { uiModules } from 'ui/modules';
+import { IRouter } from 'src/core/server';
 
-// add the module deps to this module
-uiModules.get('apps/management');
+export const registerGetAllowedTypesRoute = (router: IRouter) => {
+  router.get(
+    {
+      path: '/api/kibana/management/saved_objects/_allowed_types',
+      validate: false,
+    },
+    async (context, req, res) => {
+      const allowedTypes = context.core.savedObjects.typeRegistry
+        .getImportableAndExportableTypes()
+        .map(type => type.name);
 
-management.getSection('kibana').register('objects', {
-  display: i18n.translate('kbn.management.objects.savedObjectsSectionLabel', {
-    defaultMessage: 'Saved Objects',
-  }),
-  order: 10,
-  url: '#/management/kibana/objects',
-});
+      return res.ok({
+        body: {
+          types: allowedTypes,
+        },
+      });
+    }
+  );
+};
diff --git a/src/plugins/saved_objects_management/server/routes/index.test.ts b/src/plugins/saved_objects_management/server/routes/index.test.ts
index f183972953dce..237760444f04e 100644
--- a/src/plugins/saved_objects_management/server/routes/index.test.ts
+++ b/src/plugins/saved_objects_management/server/routes/index.test.ts
@@ -34,7 +34,7 @@ describe('registerRoutes', () => {
     });
 
     expect(httpSetup.createRouter).toHaveBeenCalledTimes(1);
-    expect(router.get).toHaveBeenCalledTimes(2);
+    expect(router.get).toHaveBeenCalledTimes(3);
     expect(router.post).toHaveBeenCalledTimes(2);
 
     expect(router.get).toHaveBeenCalledWith(
@@ -49,6 +49,12 @@ describe('registerRoutes', () => {
       }),
       expect.any(Function)
     );
+    expect(router.get).toHaveBeenCalledWith(
+      expect.objectContaining({
+        path: '/api/kibana/management/saved_objects/_allowed_types',
+      }),
+      expect.any(Function)
+    );
     expect(router.post).toHaveBeenCalledWith(
       expect.objectContaining({
         path: '/api/kibana/management/saved_objects/scroll/counts',
diff --git a/src/plugins/saved_objects_management/server/routes/index.ts b/src/plugins/saved_objects_management/server/routes/index.ts
index 2c6adb71ed3ce..0929de56b215e 100644
--- a/src/plugins/saved_objects_management/server/routes/index.ts
+++ b/src/plugins/saved_objects_management/server/routes/index.ts
@@ -23,6 +23,7 @@ import { registerFindRoute } from './find';
 import { registerScrollForCountRoute } from './scroll_count';
 import { registerScrollForExportRoute } from './scroll_export';
 import { registerRelationshipsRoute } from './relationships';
+import { registerGetAllowedTypesRoute } from './get_allowed_types';
 
 interface RegisterRouteOptions {
   http: HttpServiceSetup;
@@ -35,4 +36,5 @@ export function registerRoutes({ http, managementServicePromise }: RegisterRoute
   registerScrollForCountRoute(router);
   registerScrollForExportRoute(router);
   registerRelationshipsRoute(router, managementServicePromise);
+  registerGetAllowedTypesRoute(router);
 }
diff --git a/src/plugins/saved_objects_management/server/types.ts b/src/plugins/saved_objects_management/server/types.ts
index 5c4763d357e87..bd17d6a19ae70 100644
--- a/src/plugins/saved_objects_management/server/types.ts
+++ b/src/plugins/saved_objects_management/server/types.ts
@@ -17,38 +17,10 @@
  * under the License.
  */
 
-import { SavedObject } from 'src/core/server';
-
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
 export interface SavedObjectsManagementPluginSetup {}
 
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
 export interface SavedObjectsManagementPluginStart {}
 
-/**
- * The metadata injected into a {@link SavedObject | saved object} when returning
- * {@link SavedObjectWithMetadata | enhanced objects} from the plugin API endpoints.
- */
-export interface SavedObjectMetadata {
-  icon?: string;
-  title?: string;
-  editUrl?: string;
-  inAppUrl?: { path: string; uiCapabilitiesPath: string };
-}
-
-/**
- * A {@link SavedObject | saved object} enhanced with meta properties used by the client-side plugin.
- */
-export type SavedObjectWithMetadata<T = unknown> = SavedObject<T> & {
-  meta: SavedObjectMetadata;
-};
-
-/**
- * Represents a relation between two {@link SavedObject | saved object}
- */
-export interface SavedObjectRelation {
-  id: string;
-  type: string;
-  relationship: 'child' | 'parent';
-  meta: SavedObjectMetadata;
-}
+export { SavedObjectMetadata, SavedObjectWithMetadata, SavedObjectRelation } from '../common';
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.test.ts b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.test.ts
index 7d680f0ee0ed6..4e61756d933c9 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.test.ts
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.test.ts
@@ -22,8 +22,8 @@ describe('CopySavedObjectsToSpaceService', () => {
       const service = new CopySavedObjectsToSpaceService();
       service.setup(deps);
 
-      expect(deps.savedObjectsManagementSetup.actionRegistry.register).toHaveBeenCalledTimes(1);
-      expect(deps.savedObjectsManagementSetup.actionRegistry.register).toHaveBeenCalledWith(
+      expect(deps.savedObjectsManagementSetup.actions.register).toHaveBeenCalledTimes(1);
+      expect(deps.savedObjectsManagementSetup.actions.register).toHaveBeenCalledWith(
         expect.any(CopyToSpaceSavedObjectsManagementAction)
       );
     });
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.ts b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.ts
index d564514beebff..93d0f92744d41 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.ts
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_service.ts
@@ -18,6 +18,6 @@ interface SetupDeps {
 export class CopySavedObjectsToSpaceService {
   public setup({ spacesManager, savedObjectsManagementSetup, notificationsSetup }: SetupDeps) {
     const action = new CopyToSpaceSavedObjectsManagementAction(spacesManager, notificationsSetup);
-    savedObjectsManagementSetup.actionRegistry.register(action);
+    savedObjectsManagementSetup.actions.register(action);
   }
 }
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index fe0c58e83e544..e579830bad203 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -2011,7 +2011,6 @@
     "kbn.dashboard.listing.table.descriptionColumnName": "説明",
     "kbn.dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage": "「6.1.0」のダッシュボードの互換性のため、パネルデータを移行できませんでした。パネルには想定された列または行フィールドがありません",
     "kbn.dashboard.panel.unableToMigratePanelDataForSixThreeZeroErrorMessage": "「6.3.0」のダッシュボードの互換性のため、パネルデータを移行できませんでした。パネルに必要なフィールドがありません: {key}",
-    "kbn.dashboard.savedDashboardsTitle": "ダッシュボード",
     "kbn.dashboardTitle": "ダッシュボード",
     "kbn.devToolsTitle": "開発ツール",
     "kbn.discover.backToTopLinkText": "最上部へ戻る。",
@@ -2281,9 +2280,6 @@
     "kbn.management.editIndexPattern.timeFilterLabel.mappingAPILink": "マッピング API",
     "kbn.management.editIndexPattern.timeFilterLabel.timeFilterDetail": "このページは {indexPatternTitle} インデックス内のすべてのフィールドと、Elasticsearch に記録された各フィールドのコアタイプを一覧表示します。フィールドタイプを変更するには Elasticsearch を使用します",
     "kbn.management.editIndexPatternLiveRegionAriaLabel": "インデックスパターン",
-    "kbn.management.indexPattern.confirmOverwriteButton": "上書き",
-    "kbn.management.indexPattern.confirmOverwriteLabel": "「{title}」に上書きしてよろしいですか?",
-    "kbn.management.indexPattern.confirmOverwriteTitle": "{type} を上書きしますか?",
     "kbn.management.indexPattern.goToPatternButtonLabel": "既存のパターンに移動",
     "kbn.management.indexPattern.sectionsHeader": "インデックスパターン",
     "kbn.management.indexPattern.titleExistsLabel": "「{title}」というタイトルのインデックスパターンが既に存在します。",
@@ -2306,125 +2302,128 @@
     "kbn.management.indexPatternTable.title": "インデックスパターン",
     "kbn.management.landing.header": "Kibana {version} 管理",
     "kbn.management.landing.subhead": "インデックス、インデックスパターン、保存されたオブジェクト、Kibana の設定、その他を管理します。",
-    "kbn.management.landing.text": "アプリの一覧は左側のメニューにあります。",
-    "kbn.management.objects.confirmModalOptions.deleteButtonLabel": "削除",
-    "kbn.management.objects.confirmModalOptions.modalDescription": "このアクションはオブジェクトを Kibana から永久に削除します。",
-    "kbn.management.objects.confirmModalOptions.modalTitle": "「{title}」を削除しますか?",
-    "kbn.management.objects.deleteSavedObjectsConfirmModalDescription": "この操作は次の保存されたオブジェクトを削除します:",
-    "kbn.management.objects.field.offLabel": "オフ",
-    "kbn.management.objects.field.onLabel": "オン",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "キャンセル",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel": "削除",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel": "削除中…",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.idColumnName": "ID",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName": "タイトル",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName": "タイプ",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModalTitle": "保存されたオブジェクトの削除",
-    "kbn.management.objects.objectsTable.export.dangerNotification": "エクスポートを生成できません",
-    "kbn.management.objects.objectsTable.export.successNotification": "ファイルはバックグラウンドでダウンロード中です",
-    "kbn.management.objects.objectsTable.export.successWithMissingRefsNotification": "ファイルはバックグラウンドでダウンロード中です。一部の関連オブジェクトが見つかりませんでした。足りないオブジェクトの一覧は、エクスポートされたファイルの最後の行をご覧ください。",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.cancelButtonLabel": "キャンセル",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel": "すべてエクスポート:",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportOptionsLabel": "オプション",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel": "関連オブジェクトを含める",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModalDescription": "エクスポートするタイプを選択してください",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModalTitle": "{filteredItemCount, plural, one{# オブジェクト} other {# オブジェクト}}をエクスポート",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage": "矛盾を解決中…",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage": "失敗したオブジェクトを再試行中…",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage": "保存された検索が正しくリンクされていることを確認してください…",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage": "矛盾を保存中…",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteBody": "{title} を上書きしてよろしいですか?",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteCancelButtonText": "キャンセル",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteOverwriteButtonText": "上書き",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteTitle": "{type} を上書きしますか?",
-    "kbn.management.objects.objectsTable.flyout.errorCalloutTitle": "申し訳ございませんが、エラーが発生しました",
-    "kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel": "キャンセル",
-    "kbn.management.objects.objectsTable.flyout.import.confirmButtonLabel": "インポート",
-    "kbn.management.objects.objectsTable.flyout.importFailedDescription": "{totalImportCount} 個中 {failedImportCount} 個のオブジェクトのインポートに失敗しました。インポート失敗",
-    "kbn.management.objects.objectsTable.flyout.importFailedMissingReference": "{type} [id={id}] は {refType} [id={refId}] を見つけられませんでした",
-    "kbn.management.objects.objectsTable.flyout.importFailedTitle": "インポート失敗",
-    "kbn.management.objects.objectsTable.flyout.importFailedUnsupportedType": "{type} [id={id}] サポートされていないタイプ",
-    "kbn.management.objects.objectsTable.flyout.importFileErrorMessage": "ファイルを処理できませんでした。",
-    "kbn.management.objects.objectsTable.flyout.importLegacyFileErrorMessage": "ファイルを処理できませんでした。",
-    "kbn.management.objects.objectsTable.flyout.importPromptText": "インポート",
-    "kbn.management.objects.objectsTable.flyout.importSavedObjectTitle": "保存されたオブジェクトのインポート",
-    "kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel": "すべての変更を確定",
-    "kbn.management.objects.objectsTable.flyout.importSuccessful.confirmButtonLabel": "完了",
-    "kbn.management.objects.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle": "オブジェクトがインポートされませんでした",
-    "kbn.management.objects.objectsTable.flyout.importSuccessfulDescription": "{importCount} 個のオブジェクトがインポートされました。",
-    "kbn.management.objects.objectsTable.flyout.importSuccessfulTitle": "インポート成功",
-    "kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText": "新規インデックスパターンを作成",
-    "kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription": "次の保存されたオブジェクトは、存在しないインデックスパターンを使用しています。別のデックスパターンを選択してください。必要に応じて {indexPatternLink} できます。",
-    "kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle": "インデックスパターンの矛盾",
-    "kbn.management.objects.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage": "保存されたオブジェクトのファイル形式が無効なため、インポートできません。",
-    "kbn.management.objects.objectsTable.flyout.legacyFileUsedBody": "最新のレポートで NDJSON ファイルを作成すれば完了です。",
-    "kbn.management.objects.objectsTable.flyout.legacyFileUsedTitle": "JSON ファイルのサポートが終了します",
-    "kbn.management.objects.objectsTable.flyout.overwriteSavedObjectsLabel": "すべての保存されたオブジェクトを自動的に上書きしますか?",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountDescription": "影響されるオブジェクトの数です",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountName": "カウント",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdDescription": "インデックスパターンの ID です",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdName": "ID",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnNewIndexPatternName": "新規インデックスパターン",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription": "影響されるオブジェクトのサンプルです",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName": "影響されるオブジェクトのサンプル",
-    "kbn.management.objects.objectsTable.flyout.resolveImportErrorsFileErrorMessage": "ファイルを処理できませんでした。",
-    "kbn.management.objects.objectsTable.flyout.selectFileToImportFormRowLabel": "インポートするファイルを選択してください",
-    "kbn.management.objects.objectsTable.header.exportButtonLabel": "{filteredCount, plural, one{# オブジェクト} other {# オブジェクト}}をエクスポート",
-    "kbn.management.objects.objectsTable.header.importButtonLabel": "インポート",
-    "kbn.management.objects.objectsTable.header.refreshButtonLabel": "更新",
-    "kbn.management.objects.objectsTable.header.savedObjectsTitle": "保存されたオブジェクト",
-    "kbn.management.objects.objectsTable.howToDeleteSavedObjectsDescription": "ここから保存された検索などの保存されたオブジェクトを削除できます。保存されたオブジェクトの生データを編集することもできます。通常、オブジェクトは関連アプリケーションでのみ編集され、こn画面で編集するよりもそちらのほうが賢明です。",
-    "kbn.management.objects.objectsTable.relationships.columnActions.inspectActionDescription": "この保存されたオブジェクトを確認してください",
-    "kbn.management.objects.objectsTable.relationships.columnActions.inspectActionName": "検査",
-    "kbn.management.objects.objectsTable.relationships.columnActionsName": "アクション",
-    "kbn.management.objects.objectsTable.relationships.columnRelationship.childAsValue": "子",
-    "kbn.management.objects.objectsTable.relationships.columnRelationship.parentAsValue": "ペアレント",
-    "kbn.management.objects.objectsTable.relationships.columnRelationshipName": "直接関係",
-    "kbn.management.objects.objectsTable.relationships.columnTitleDescription": "保存されたオブジェクトのタイトルです",
-    "kbn.management.objects.objectsTable.relationships.columnTitleName": "タイトル",
-    "kbn.management.objects.objectsTable.relationships.columnTypeDescription": "保存されたオブジェクトのタイプです",
-    "kbn.management.objects.objectsTable.relationships.columnTypeName": "タイプ",
-    "kbn.management.objects.objectsTable.relationships.relationshipsTitle": "{title} に関連する保存されたオブジェクトはこちらです。この {type} を削除すると、親オブジェクトに影響がありますが、子オブジェクトには影響はありません。",
-    "kbn.management.objects.objectsTable.relationships.renderErrorMessage": "エラー",
-    "kbn.management.objects.objectsTable.relationships.search.filters.relationship.childAsValue.view": "子",
-    "kbn.management.objects.objectsTable.relationships.search.filters.relationship.name": "直接関係",
-    "kbn.management.objects.objectsTable.relationships.search.filters.relationship.parentAsValue.view": "親",
-    "kbn.management.objects.objectsTable.relationships.search.filters.type.name": "タイプ",
-    "kbn.management.objects.objectsTable.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません",
-    "kbn.management.objects.objectsTable.table.columnActions.inspectActionDescription": "この保存されたオブジェクトを確認してください",
-    "kbn.management.objects.objectsTable.table.columnActions.inspectActionName": "検査",
-    "kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionDescription": "この保存されたオブジェクトと他の保存されたオブジェクトとの関係性を表示します",
-    "kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionName": "関係性",
-    "kbn.management.objects.objectsTable.table.columnActionsName": "アクション",
-    "kbn.management.objects.objectsTable.table.columnTitleDescription": "保存されたオブジェクトのタイトルです",
-    "kbn.management.objects.objectsTable.table.columnTitleName": "タイトル",
-    "kbn.management.objects.objectsTable.table.columnTypeDescription": "保存されたオブジェクトのタイプです",
-    "kbn.management.objects.objectsTable.table.columnTypeName": "タイプ",
-    "kbn.management.objects.objectsTable.table.deleteButtonLabel": "削除",
-    "kbn.management.objects.objectsTable.table.deleteButtonTitle": "保存されたオブジェクトを削除できません",
-    "kbn.management.objects.objectsTable.table.exportButtonLabel": "エクスポート",
-    "kbn.management.objects.objectsTable.table.exportPopoverButtonLabel": "エクスポート",
-    "kbn.management.objects.objectsTable.table.typeFilterName": "タイプ",
-    "kbn.management.objects.objectsTable.unableFindSavedObjectsNotificationMessage": "保存されたオブジェクトが見つかりません",
-    "kbn.management.objects.parsingFieldErrorMessage": "{fieldName} をインデックスパターン {indexName} 用にパース中にエラーが発生しました: {errorMessage}",
-    "kbn.management.objects.savedObjectsSectionLabel": "保存されたオブジェクト",
-    "kbn.management.objects.view.cancelButtonAriaLabel": "キャンセル",
-    "kbn.management.objects.view.cancelButtonLabel": "キャンセル",
-    "kbn.management.objects.view.deleteItemButtonLabel": "{title} を削除",
-    "kbn.management.objects.view.editItemTitle": "{title} の編集",
-    "kbn.management.objects.view.fieldDoesNotExistErrorMessage": "このオブジェクトに関連付けられたフィールドは、現在このインデックスパターンに存在しません。",
-    "kbn.management.objects.view.howToFixErrorDescription": "このエラーの原因がわかる場合は修正してください。わからない場合は上の削除ボタンをクリックしてください。",
-    "kbn.management.objects.view.howToModifyObjectDescription": "オブジェクトの編集は上級ユーザー向けです。オブジェクトのプロパティが検証されておらず、無効なオブジェクトはエラー、データ損失、またはそれ以上の問題の原因となります。コードを熟知した人に指示されていない限り、この設定は変更しない方が無難です。",
-    "kbn.management.objects.view.howToModifyObjectTitle": "十分ご注意ください!",
-    "kbn.management.objects.view.indexPatternDoesNotExistErrorMessage": "このオブジェクトに関連付けられたインデックスパターンは現在存在しません。",
-    "kbn.management.objects.view.saveButtonAriaLabel": "{ title } オブジェクトを保存",
-    "kbn.management.objects.view.saveButtonLabel": "{ title } オブジェクトを保存",
-    "kbn.management.objects.view.savedObjectProblemErrorMessage": "この保存されたオブジェクトに問題があります",
-    "kbn.management.objects.view.savedSearchDoesNotExistErrorMessage": "このオブジェクトに関連付けられた保存された検索は現在存在しません。",
-    "kbn.management.objects.view.viewItemButtonLabel": "{title} を表示",
-    "kbn.management.objects.view.viewItemTitle": "{title} を表示",
-    "kbn.management.savedObjects.editBreadcrumb": "{savedObjectType} を編集",
-    "kbn.management.savedObjects.indexBreadcrumb": "保存されたオブジェクト",
+    "kbn.management.landing.text": "すべてのツールの一覧は、左のメニューにあります。",
+    "savedObjectsManagement.indexPattern.confirmOverwriteButton": "上書き",
+    "savedObjectsManagement.indexPattern.confirmOverwriteLabel": "「{title}」に上書きしてよろしいですか?",
+    "savedObjectsManagement.indexPattern.confirmOverwriteTitle": "{type} を上書きしますか?",
+    "savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel": "削除",
+    "savedObjectsManagement.deleteConfirm.modalDescription": "このアクションはオブジェクトを Kibana から永久に削除します。",
+    "savedObjectsManagement.deleteConfirm.modalTitle": "「{title}」を削除しますか?",
+    "savedObjectsManagement.deleteSavedObjectsConfirmModalDescription": "この操作は次の保存されたオブジェクトを削除します:",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "キャンセル",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel": "削除",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel": "削除中…",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName": "ID",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName": "タイトル",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName": "タイプ",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModalTitle": "保存されたオブジェクトの削除",
+    "savedObjectsManagement.objectsTable.export.dangerNotification": "エクスポートを生成できません",
+    "savedObjectsManagement.objectsTable.export.successNotification": "ファイルはバックグラウンドでダウンロード中です",
+    "savedObjectsManagement.objectsTable.export.successWithMissingRefsNotification": "ファイルはバックグラウンドでダウンロード中です。一部の関連オブジェクトが見つかりませんでした。足りないオブジェクトの一覧は、エクスポートされたファイルの最後の行をご覧ください。",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.cancelButtonLabel": "キャンセル",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel": "すべてエクスポート:",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportOptionsLabel": "オプション",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel": "関連オブジェクトを含める",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription": "エクスポートするタイプを選択してください",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle": "{filteredItemCount, plural, one{# オブジェクト} other {# オブジェクト}}をエクスポート",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage": "矛盾を解決中…",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage": "失敗したオブジェクトを再試行中…",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage": "保存された検索が正しくリンクされていることを確認してください…",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage": "矛盾を保存中…",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteBody": "{title} を上書きしてよろしいですか?",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteCancelButtonText": "キャンセル",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteOverwriteButtonText": "上書き",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteTitle": "{type} を上書きしますか?",
+    "savedObjectsManagement.objectsTable.flyout.errorCalloutTitle": "申し訳ございませんが、エラーが発生しました",
+    "savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel": "キャンセル",
+    "savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel": "インポート",
+    "savedObjectsManagement.objectsTable.flyout.importFailedDescription": "{totalImportCount} 個中 {failedImportCount} 個のオブジェクトのインポートに失敗しました。インポート失敗",
+    "savedObjectsManagement.objectsTable.flyout.importFailedMissingReference": "{type} [id={id}] は {refType} [id={refId}] を見つけられませんでした",
+    "savedObjectsManagement.objectsTable.flyout.importFailedTitle": "インポート失敗",
+    "savedObjectsManagement.objectsTable.flyout.importFailedUnsupportedType": "{type} [id={id}] サポートされていないタイプ",
+    "savedObjectsManagement.objectsTable.flyout.importFileErrorMessage": "ファイルを処理できませんでした。",
+    "savedObjectsManagement.objectsTable.flyout.importLegacyFileErrorMessage": "ファイルを処理できませんでした。",
+    "savedObjectsManagement.objectsTable.flyout.importPromptText": "インポート",
+    "savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle": "保存されたオブジェクトのインポート",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel": "すべての変更を確定",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmButtonLabel": "完了",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle": "オブジェクトがインポートされませんでした",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessfulDescription": "{importCount} 個のオブジェクトがインポートされました。",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessfulTitle": "インポート成功",
+    "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText": "新規インデックスパターンを作成",
+    "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription": "次の保存されたオブジェクトは、存在しないインデックスパターンを使用しています。別のデックスパターンを選択してください。必要に応じて {indexPatternLink} できます。",
+    "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle": "インデックスパターンの矛盾",
+    "savedObjectsManagement.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage": "保存されたオブジェクトのファイル形式が無効なため、インポートできません。",
+    "savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody": "最新のレポートで NDJSON ファイルを作成すれば完了です。",
+    "savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle": "JSON ファイルのサポートが終了します",
+    "savedObjectsManagement.objectsTable.flyout.overwriteSavedObjectsLabel": "すべての保存されたオブジェクトを自動的に上書きしますか?",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountDescription": "影響されるオブジェクトの数です",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountName": "カウント",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdDescription": "インデックスパターンの ID です",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdName": "ID",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnNewIndexPatternName": "新規インデックスパターン",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription": "影響されるオブジェクトのサンプルです",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName": "影響されるオブジェクトのサンプル",
+    "savedObjectsManagement.objectsTable.flyout.resolveImportErrorsFileErrorMessage": "ファイルを処理できませんでした。",
+    "savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel": "インポートするファイルを選択してください",
+    "savedObjectsManagement.objectsTable.header.exportButtonLabel": "{filteredCount, plural, one{# オブジェクト} other {# オブジェクト}}をエクスポート",
+    "savedObjectsManagement.objectsTable.header.importButtonLabel": "インポート",
+    "savedObjectsManagement.objectsTable.header.refreshButtonLabel": "更新",
+    "savedObjectsManagement.objectsTable.header.savedObjectsTitle": "保存されたオブジェクト",
+    "savedObjectsManagement.objectsTable.howToDeleteSavedObjectsDescription": "ここから保存された検索などの保存されたオブジェクトを削除できます。保存されたオブジェクトの生データを編集することもできます。通常、オブジェクトは関連アプリケーションでのみ編集され、こn画面で編集するよりもそちらのほうが賢明です。",
+    "savedObjectsManagement.objectsTable.relationships.columnActions.inspectActionDescription": "この保存されたオブジェクトを確認してください",
+    "savedObjectsManagement.objectsTable.relationships.columnActions.inspectActionName": "検査",
+    "savedObjectsManagement.objectsTable.relationships.columnActionsName": "アクション",
+    "savedObjectsManagement.objectsTable.relationships.columnRelationship.childAsValue": "子",
+    "savedObjectsManagement.objectsTable.relationships.columnRelationship.parentAsValue": "ペアレント",
+    "savedObjectsManagement.objectsTable.relationships.columnRelationshipName": "直接関係",
+    "savedObjectsManagement.objectsTable.relationships.columnTitleDescription": "保存されたオブジェクトのタイトルです",
+    "savedObjectsManagement.objectsTable.relationships.columnTitleName": "タイトル",
+    "savedObjectsManagement.objectsTable.relationships.columnTypeDescription": "保存されたオブジェクトのタイプです",
+    "savedObjectsManagement.objectsTable.relationships.columnTypeName": "タイプ",
+    "savedObjectsManagement.objectsTable.relationships.relationshipsTitle": "{title} に関連する保存されたオブジェクトはこちらです。この {type} を削除すると、親オブジェクトに影響がありますが、子オブジェクトには影響はありません。",
+    "savedObjectsManagement.objectsTable.relationships.renderErrorMessage": "エラー",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.relationship.childAsValue.view": "子",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.relationship.name": "直接関係",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.relationship.parentAsValue.view": "親",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.type.name": "タイプ",
+    "savedObjectsManagement.objectsTable.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません",
+    "savedObjectsManagement.objectsTable.table.columnActions.inspectActionDescription": "この保存されたオブジェクトを確認してください",
+    "savedObjectsManagement.objectsTable.table.columnActions.inspectActionName": "検査",
+    "savedObjectsManagement.objectsTable.table.columnActions.viewRelationshipsActionDescription": "この保存されたオブジェクトと他の保存されたオブジェクトとの関係性を表示します",
+    "savedObjectsManagement.objectsTable.table.columnActions.viewRelationshipsActionName": "関係性",
+    "savedObjectsManagement.objectsTable.table.columnActionsName": "アクション",
+    "savedObjectsManagement.objectsTable.table.columnTitleDescription": "保存されたオブジェクトのタイトルです",
+    "savedObjectsManagement.objectsTable.table.columnTitleName": "タイトル",
+    "savedObjectsManagement.objectsTable.table.columnTypeDescription": "保存されたオブジェクトのタイプです",
+    "savedObjectsManagement.objectsTable.table.columnTypeName": "タイプ",
+    "savedObjectsManagement.objectsTable.table.deleteButtonLabel": "削除",
+    "savedObjectsManagement.objectsTable.table.deleteButtonTitle": "保存されたオブジェクトを削除できません",
+    "savedObjectsManagement.objectsTable.table.exportButtonLabel": "エクスポート",
+    "savedObjectsManagement.objectsTable.table.exportPopoverButtonLabel": "エクスポート",
+    "savedObjectsManagement.objectsTable.table.typeFilterName": "タイプ",
+    "savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage": "保存されたオブジェクトが見つかりません",
+    "savedObjectsManagement.parsingFieldErrorMessage": "{fieldName} をインデックスパターン {indexName} 用にパース中にエラーが発生しました: {errorMessage}",
+    "savedObjectsManagement.managementSectionLabel": "保存されたオブジェクト",
+    "savedObjectsManagement.view.cancelButtonAriaLabel": "キャンセル",
+    "savedObjectsManagement.view.cancelButtonLabel": "キャンセル",
+    "savedObjectsManagement.view.deleteItemButtonLabel": "{title} を削除",
+    "savedObjectsManagement.view.editItemTitle": "{title} の編集",
+    "savedObjectsManagement.view.fieldDoesNotExistErrorMessage": "このオブジェクトに関連付けられたフィールドは、現在このインデックスパターンに存在しません。",
+    "savedObjectsManagement.view.howToFixErrorDescription": "このエラーの原因がわかる場合は修正してください。わからない場合は上の削除ボタンをクリックしてください。",
+    "savedObjectsManagement.view.howToModifyObjectDescription": " オブジェクトの編集は上級ユーザー向けです。オブジェクトのプロパティが検証されておらず、無効なオブジェクトはエラー、データ損失、またはそれ以上の問題の原因となります。コードを熟知した人に指示されていない限り、この設定は変更しない方が無難です。",
+    "savedObjectsManagement.view.howToModifyObjectTitle": "十分ご注意ください!",
+    "savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "このオブジェクトに関連付けられたインデックスパターンは現在存在しません。",
+    "savedObjectsManagement.view.saveButtonAriaLabel": "{ title }  オブジェクトを保存",
+    "savedObjectsManagement.view.saveButtonLabel": "{ title }  オブジェクトを保存",
+    "savedObjectsManagement.view.savedObjectProblemErrorMessage": "この保存されたオブジェクトに問題があります",
+    "savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "このオブジェクトに関連付けられた保存された検索は現在存在しません。",
+    "savedObjectsManagement.view.viewItemButtonLabel": "{title} を表示",
+    "savedObjectsManagement.view.viewItemTitle": "{title} を表示",
+    "savedObjectsManagement.breadcrumb.edit": "{savedObjectType} を編集",
+    "savedObjectsManagement.breadcrumb.index": "保存されたオブジェクト",
+    "savedObjectsManagement.field.offLabel": "オフ",
+    "savedObjectsManagement.field.onLabel": "オン",
     "kbn.managementTitle": "管理",
     "kbn.topNavMenu.openInspectorButtonLabel": "検査",
     "kbn.topNavMenu.refreshButtonLabel": "更新",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index fd2a92c2c402f..75f48fb11823a 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -2012,7 +2012,6 @@
     "kbn.dashboard.listing.table.descriptionColumnName": "描述",
     "kbn.dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage": "无法迁移用于“6.1.0”向后兼容的面板数据,面板不包含所需的列和/或行字段",
     "kbn.dashboard.panel.unableToMigratePanelDataForSixThreeZeroErrorMessage": "无法迁移用于“6.3.0”向后兼容的面板数据,面板不包含预期字段:{key}",
-    "kbn.dashboard.savedDashboardsTitle": "仪表板",
     "kbn.dashboardTitle": "仪表板",
     "kbn.devToolsTitle": "开发工具",
     "kbn.discover.backToTopLinkText": "返至顶部。",
@@ -2282,9 +2281,6 @@
     "kbn.management.editIndexPattern.timeFilterLabel.mappingAPILink": "映射 API",
     "kbn.management.editIndexPattern.timeFilterLabel.timeFilterDetail": "此页根据 Elasticsearch 的记录列出“{indexPatternTitle}”索引中的每个字段以及字段的关联核心类型。要更改字段类型,请使用 Elasticsearch",
     "kbn.management.editIndexPatternLiveRegionAriaLabel": "索引模式",
-    "kbn.management.indexPattern.confirmOverwriteButton": "覆盖",
-    "kbn.management.indexPattern.confirmOverwriteLabel": "确定要覆盖 “{title}”?",
-    "kbn.management.indexPattern.confirmOverwriteTitle": "覆盖“{type}”?",
     "kbn.management.indexPattern.goToPatternButtonLabel": "前往现有模式",
     "kbn.management.indexPattern.sectionsHeader": "索引模式",
     "kbn.management.indexPattern.titleExistsLabel": "具有标题 “{title}” 的索引模式已存在。",
@@ -2308,124 +2304,127 @@
     "kbn.management.landing.header": "Kibana {version} 管理",
     "kbn.management.landing.subhead": "管理您的索引、索引模式、已保存对象、Kibana 设置等等。",
     "kbn.management.landing.text": "应用的完整列表位于左侧菜单中。",
-    "kbn.management.objects.confirmModalOptions.deleteButtonLabel": "删除",
-    "kbn.management.objects.confirmModalOptions.modalDescription": "此操作会将对象从 Kibana 永久移除。",
-    "kbn.management.objects.confirmModalOptions.modalTitle": "删除“{title}”?",
-    "kbn.management.objects.deleteSavedObjectsConfirmModalDescription": "此操作将删除以下已保存对象:",
-    "kbn.management.objects.field.offLabel": "关闭",
-    "kbn.management.objects.field.onLabel": "开启",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "取消",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel": "删除",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel": "正在删除……",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.idColumnName": "ID",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName": "标题",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName": "类型",
-    "kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModalTitle": "删除已保存对象",
-    "kbn.management.objects.objectsTable.export.dangerNotification": "无法生成报告",
-    "kbn.management.objects.objectsTable.export.successNotification": "您的文件正在后台下载",
-    "kbn.management.objects.objectsTable.export.successWithMissingRefsNotification": "您的文件正在后台下载。找不到某些相关对象。有关缺失对象列表,请查看导出文件的最后一行。",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.cancelButtonLabel": "取消",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel": "全部导出",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportOptionsLabel": "选项",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel": "包括相关对象",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModalDescription": "选择要导出的类型。",
-    "kbn.management.objects.objectsTable.exportObjectsConfirmModalTitle": "导出 {filteredItemCount, plural, one{# 个对象} other {# 个对象}}",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage": "正在解决冲突……",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage": "正在重试失败的对象……",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage": "确保已保存搜索已正确链接……",
-    "kbn.management.objects.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage": "正在保存冲突……",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteBody": "确定要覆盖 “{title}”?",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteCancelButtonText": "取消",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteOverwriteButtonText": "覆盖",
-    "kbn.management.objects.objectsTable.flyout.confirmOverwriteTitle": "覆盖“{type}”?",
-    "kbn.management.objects.objectsTable.flyout.errorCalloutTitle": "抱歉,出现了错误",
-    "kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel": "取消",
-    "kbn.management.objects.objectsTable.flyout.import.confirmButtonLabel": "导入",
-    "kbn.management.objects.objectsTable.flyout.importFailedDescription": "无法导入 {failedImportCount} 个对象,共 {totalImportCount} 个。导入失败",
-    "kbn.management.objects.objectsTable.flyout.importFailedMissingReference": "{type} [id={id}] 无法找到 {refType} [id={refId}]",
-    "kbn.management.objects.objectsTable.flyout.importFailedTitle": "导入失败",
-    "kbn.management.objects.objectsTable.flyout.importFailedUnsupportedType": "{type} [id={id}] 不受支持的类型",
-    "kbn.management.objects.objectsTable.flyout.importFileErrorMessage": "无法处理该文件。",
-    "kbn.management.objects.objectsTable.flyout.importLegacyFileErrorMessage": "无法处理该文件。",
-    "kbn.management.objects.objectsTable.flyout.importPromptText": "导入",
-    "kbn.management.objects.objectsTable.flyout.importSavedObjectTitle": "导入已保存对象",
-    "kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel": "确认所有更改",
-    "kbn.management.objects.objectsTable.flyout.importSuccessful.confirmButtonLabel": "完成",
-    "kbn.management.objects.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle": "未导入任何对象",
-    "kbn.management.objects.objectsTable.flyout.importSuccessfulDescription": "已成功导入 {importCount} 个对象。",
-    "kbn.management.objects.objectsTable.flyout.importSuccessfulTitle": "导入成功",
-    "kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText": "创建新的索引模式",
-    "kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription": "以下已保存对象使用不存在的索引模式。请选择要重新关联的索引模式。必要时,您可以{indexPatternLink}。",
-    "kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle": "索引模式冲突",
-    "kbn.management.objects.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage": "已保存对象文件格式无效,无法导入。",
-    "kbn.management.objects.objectsTable.flyout.legacyFileUsedBody": "只需使用更新的导出功能生成 NDJSON 文件,便万事俱备。",
-    "kbn.management.objects.objectsTable.flyout.legacyFileUsedTitle": "将不再支持 JSON 文件",
-    "kbn.management.objects.objectsTable.flyout.overwriteSavedObjectsLabel": "自动覆盖所有已保存对象?",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountDescription": "受影响对象数目",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountName": "计数",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdDescription": "索引模式的 ID",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdName": "ID",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnNewIndexPatternName": "新建索引模式",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription": "受影响对象样例",
-    "kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName": "受影响对象样例",
-    "kbn.management.objects.objectsTable.flyout.resolveImportErrorsFileErrorMessage": "无法处理该文件。",
-    "kbn.management.objects.objectsTable.flyout.selectFileToImportFormRowLabel": "请选择要导入的文件",
-    "kbn.management.objects.objectsTable.header.exportButtonLabel": "导出 {filteredCount, plural, one{# 个对象} other {# 个对象}}",
-    "kbn.management.objects.objectsTable.header.importButtonLabel": "导入",
-    "kbn.management.objects.objectsTable.header.refreshButtonLabel": "刷新",
-    "kbn.management.objects.objectsTable.header.savedObjectsTitle": "已保存对象",
-    "kbn.management.objects.objectsTable.howToDeleteSavedObjectsDescription": "从这里您可以删除已保存对象,如已保存搜索。还可以编辑已保存对象的原始数据。通常,对象只能通过其关联的应用程序进行修改;或许您应该遵循这一原则,而非使用此屏幕进行修改。",
-    "kbn.management.objects.objectsTable.relationships.columnActions.inspectActionDescription": "检查此已保存对象",
-    "kbn.management.objects.objectsTable.relationships.columnActions.inspectActionName": "检查",
-    "kbn.management.objects.objectsTable.relationships.columnActionsName": "操作",
-    "kbn.management.objects.objectsTable.relationships.columnRelationship.childAsValue": "子项",
-    "kbn.management.objects.objectsTable.relationships.columnRelationship.parentAsValue": "父项",
-    "kbn.management.objects.objectsTable.relationships.columnRelationshipName": "直接关系",
-    "kbn.management.objects.objectsTable.relationships.columnTitleDescription": "已保存对象的标题",
-    "kbn.management.objects.objectsTable.relationships.columnTitleName": "标题",
-    "kbn.management.objects.objectsTable.relationships.columnTypeDescription": "已保存对象的类型",
-    "kbn.management.objects.objectsTable.relationships.columnTypeName": "类型",
-    "kbn.management.objects.objectsTable.relationships.relationshipsTitle": "以下是与 {title} 相关的已保存对象。删除此{type}将影响其父级对象,但不会影响其子级对象。",
-    "kbn.management.objects.objectsTable.relationships.renderErrorMessage": "错误",
-    "kbn.management.objects.objectsTable.relationships.search.filters.relationship.childAsValue.view": "子项",
-    "kbn.management.objects.objectsTable.relationships.search.filters.relationship.name": "直接关系",
-    "kbn.management.objects.objectsTable.relationships.search.filters.relationship.parentAsValue.view": "父项",
-    "kbn.management.objects.objectsTable.relationships.search.filters.type.name": "类型",
-    "kbn.management.objects.objectsTable.searchBar.unableToParseQueryErrorMessage": "无法解析查询",
-    "kbn.management.objects.objectsTable.table.columnActions.inspectActionDescription": "检查此已保存对象",
-    "kbn.management.objects.objectsTable.table.columnActions.inspectActionName": "检查",
-    "kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionDescription": "查看此已保存对象与其他已保存对象的关系",
-    "kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionName": "关系",
-    "kbn.management.objects.objectsTable.table.columnActionsName": "操作",
-    "kbn.management.objects.objectsTable.table.columnTitleDescription": "已保存对象的标题",
-    "kbn.management.objects.objectsTable.table.columnTitleName": "标题",
-    "kbn.management.objects.objectsTable.table.columnTypeDescription": "已保存对象的类型",
-    "kbn.management.objects.objectsTable.table.columnTypeName": "类型",
-    "kbn.management.objects.objectsTable.table.deleteButtonLabel": "删除",
-    "kbn.management.objects.objectsTable.table.deleteButtonTitle": "无法删除已保存对象",
-    "kbn.management.objects.objectsTable.table.exportButtonLabel": "导出",
-    "kbn.management.objects.objectsTable.table.exportPopoverButtonLabel": "导出",
-    "kbn.management.objects.objectsTable.table.typeFilterName": "类型",
-    "kbn.management.objects.objectsTable.unableFindSavedObjectsNotificationMessage": "找不到已保存对象",
-    "kbn.management.objects.parsingFieldErrorMessage": "为索引模式 “{indexName}” 解析 “{fieldName}” 时发生错误:{errorMessage}",
-    "kbn.management.objects.savedObjectsSectionLabel": "已保存对象",
-    "kbn.management.objects.view.cancelButtonAriaLabel": "取消",
-    "kbn.management.objects.view.cancelButtonLabel": "取消",
-    "kbn.management.objects.view.deleteItemButtonLabel": "删除“{title}”",
-    "kbn.management.objects.view.editItemTitle": "编辑“{title}",
-    "kbn.management.objects.view.fieldDoesNotExistErrorMessage": "与此对象关联的字段在该索引模式中已不存在。",
-    "kbn.management.objects.view.howToFixErrorDescription": "如果您清楚此错误的含义,请修复该错误 — 否则单击上面的删除按钮。",
-    "kbn.management.objects.view.howToModifyObjectDescription": "修改对象仅适用于高级用户。对象属性未得到验证,无效的对象可能会导致错误、数据丢失或更坏的情况发生。除非熟悉该代码的人让您来这里,否则您可能不应该来这里。",
-    "kbn.management.objects.view.howToModifyObjectTitle": "谨慎操作!",
-    "kbn.management.objects.view.indexPatternDoesNotExistErrorMessage": "与此对象关联的索引模式已不存在。",
-    "kbn.management.objects.view.saveButtonAriaLabel": "保存 { title } 对象",
-    "kbn.management.objects.view.saveButtonLabel": "保存 { title } 对象",
-    "kbn.management.objects.view.savedObjectProblemErrorMessage": "此已保存对象有问题",
-    "kbn.management.objects.view.savedSearchDoesNotExistErrorMessage": "与此对象关联的已保存搜索已不存在。",
-    "kbn.management.objects.view.viewItemButtonLabel": "查看“{title}”",
-    "kbn.management.objects.view.viewItemTitle": "查看“{title}”",
-    "kbn.management.savedObjects.editBreadcrumb": "编辑 {savedObjectType}",
-    "kbn.management.savedObjects.indexBreadcrumb": "已保存对象",
+    "savedObjectsManagement.indexPattern.confirmOverwriteButton": "覆盖",
+    "savedObjectsManagement.indexPattern.confirmOverwriteLabel": "确定要覆盖 “{title}”?",
+    "savedObjectsManagement.indexPattern.confirmOverwriteTitle": "覆盖“{type}”?",
+    "savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel": "删除",
+    "savedObjectsManagement.deleteConfirm.modalDescription": "此操作会将对象从 Kibana 永久移除。",
+    "savedObjectsManagement.deleteConfirm.modalTitle": "删除“{title}”?",
+    "savedObjectsManagement.deleteSavedObjectsConfirmModalDescription": "此操作将删除以下已保存对象:",
+    "savedObjectsManagement.field.offLabel": "关闭",
+    "savedObjectsManagement.field.onLabel": "开启",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "取消",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel": "删除",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel": "正在删除……",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName": "ID",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName": "标题",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName": "类型",
+    "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModalTitle": "删除已保存对象",
+    "savedObjectsManagement.objectsTable.export.dangerNotification": "无法生成报告",
+    "savedObjectsManagement.objectsTable.export.successNotification": "您的文件正在后台下载",
+    "savedObjectsManagement.objectsTable.export.successWithMissingRefsNotification": "您的文件正在后台下载。找不到某些相关对象。有关缺失对象列表,请查看导出文件的最后一行。",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.cancelButtonLabel": "取消",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel": "全部导出",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportOptionsLabel": "选项",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel": "包括相关对象",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription": "选择要导出的类型。",
+    "savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle": "导出 {filteredItemCount, plural, one{# 个对象} other {# 个对象}}",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage": "正在解决冲突……",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage": "正在重试失败的对象……",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage": "确保已保存搜索已正确链接……",
+    "savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage": "正在保存冲突……",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteBody": "确定要覆盖 “{title}”?",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteCancelButtonText": "取消",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteOverwriteButtonText": "覆盖",
+    "savedObjectsManagement.objectsTable.flyout.confirmOverwriteTitle": "覆盖“{type}”?",
+    "savedObjectsManagement.objectsTable.flyout.errorCalloutTitle": "抱歉,出现了错误",
+    "savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel": "取消",
+    "savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel": "导入",
+    "savedObjectsManagement.objectsTable.flyout.importFailedDescription": "无法导入 {failedImportCount} 个对象,共 {totalImportCount} 个。导入失败",
+    "savedObjectsManagement.objectsTable.flyout.importFailedMissingReference": "{type} [id={id}] 无法找到 {refType} [id={refId}]",
+    "savedObjectsManagement.objectsTable.flyout.importFailedTitle": "导入失败",
+    "savedObjectsManagement.objectsTable.flyout.importFailedUnsupportedType": "{type} [id={id}] 不受支持的类型",
+    "savedObjectsManagement.objectsTable.flyout.importFileErrorMessage": "无法处理该文件。",
+    "savedObjectsManagement.objectsTable.flyout.importLegacyFileErrorMessage": "无法处理该文件。",
+    "savedObjectsManagement.objectsTable.flyout.importPromptText": "导入",
+    "savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle": "导入已保存对象",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel": "确认所有更改",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmButtonLabel": "完成",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle": "未导入任何对象",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessfulDescription": "已成功导入 {importCount} 个对象。",
+    "savedObjectsManagement.objectsTable.flyout.importSuccessfulTitle": "导入成功",
+    "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText": "创建新的索引模式",
+    "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription": "以下已保存对象使用不存在的索引模式。请选择要重新关联的索引模式。必要时,您可以{indexPatternLink}。",
+    "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle": "索引模式冲突",
+    "savedObjectsManagement.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage": "已保存对象文件格式无效,无法导入。",
+    "savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody": "只需使用更新的导出功能生成 NDJSON 文件,便万事俱备。",
+    "savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle": "将不再支持 JSON 文件",
+    "savedObjectsManagement.objectsTable.flyout.overwriteSavedObjectsLabel": "自动覆盖所有已保存对象?",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountDescription": "受影响对象数目",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountName": "计数",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdDescription": "索引模式的 ID",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdName": "ID",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnNewIndexPatternName": "新建索引模式",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription": "受影响对象样例",
+    "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName": "受影响对象样例",
+    "savedObjectsManagement.objectsTable.flyout.resolveImportErrorsFileErrorMessage": "无法处理该文件。",
+    "savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel": "请选择要导入的文件",
+    "savedObjectsManagement.objectsTable.header.exportButtonLabel": "导出 {filteredCount, plural, one{# 个对象} other {# 个对象}}",
+    "savedObjectsManagement.objectsTable.header.importButtonLabel": "导入",
+    "savedObjectsManagement.objectsTable.header.refreshButtonLabel": "刷新",
+    "savedObjectsManagement.objectsTable.header.savedObjectsTitle": "已保存对象",
+    "savedObjectsManagement.objectsTable.howToDeleteSavedObjectsDescription": "从这里您可以删除已保存对象,如已保存搜索。还可以编辑已保存对象的原始数据。通常,对象只能通过其关联的应用程序进行修改;或许您应该遵循这一原则,而非使用此屏幕进行修改。",
+    "savedObjectsManagement.objectsTable.relationships.columnActions.inspectActionDescription": "检查此已保存对象",
+    "savedObjectsManagement.objectsTable.relationships.columnActions.inspectActionName": "检查",
+    "savedObjectsManagement.objectsTable.relationships.columnActionsName": "操作",
+    "savedObjectsManagement.objectsTable.relationships.columnRelationship.childAsValue": "子项",
+    "savedObjectsManagement.objectsTable.relationships.columnRelationship.parentAsValue": "父项",
+    "savedObjectsManagement.objectsTable.relationships.columnRelationshipName": "直接关系",
+    "savedObjectsManagement.objectsTable.relationships.columnTitleDescription": "已保存对象的标题",
+    "savedObjectsManagement.objectsTable.relationships.columnTitleName": "标题",
+    "savedObjectsManagement.objectsTable.relationships.columnTypeDescription": "已保存对象的类型",
+    "savedObjectsManagement.objectsTable.relationships.columnTypeName": "类型",
+    "savedObjectsManagement.objectsTable.relationships.relationshipsTitle": "以下是与 {title} 相关的已保存对象。删除此{type}将影响其父级对象,但不会影响其子级对象。",
+    "savedObjectsManagement.objectsTable.relationships.renderErrorMessage": "错误",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.relationship.childAsValue.view": "子项",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.relationship.name": "直接关系",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.relationship.parentAsValue.view": "父项",
+    "savedObjectsManagement.objectsTable.relationships.search.filters.type.name": "类型",
+    "savedObjectsManagement.objectsTable.searchBar.unableToParseQueryErrorMessage": "无法解析查询",
+    "savedObjectsManagement.objectsTable.table.columnActions.inspectActionDescription": "检查此已保存对象",
+    "savedObjectsManagement.objectsTable.table.columnActions.inspectActionName": "检查",
+    "savedObjectsManagement.objectsTable.table.columnActions.viewRelationshipsActionDescription": "查看此已保存对象与其他已保存对象的关系",
+    "savedObjectsManagement.objectsTable.table.columnActions.viewRelationshipsActionName": "关系",
+    "savedObjectsManagement.objectsTable.table.columnActionsName": "操作",
+    "savedObjectsManagement.objectsTable.table.columnTitleDescription": "已保存对象的标题",
+    "savedObjectsManagement.objectsTable.table.columnTitleName": "标题",
+    "savedObjectsManagement.objectsTable.table.columnTypeDescription": "已保存对象的类型",
+    "savedObjectsManagement.objectsTable.table.columnTypeName": "类型",
+    "savedObjectsManagement.objectsTable.table.deleteButtonLabel": "删除",
+    "savedObjectsManagement.objectsTable.table.deleteButtonTitle": "无法删除已保存对象",
+    "savedObjectsManagement.objectsTable.table.exportButtonLabel": "导出",
+    "savedObjectsManagement.objectsTable.table.exportPopoverButtonLabel": "导出",
+    "savedObjectsManagement.objectsTable.table.typeFilterName": "类型",
+    "savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage": "找不到已保存对象",
+    "savedObjectsManagement.parsingFieldErrorMessage": "为索引模式 “{indexName}” 解析 “{fieldName}” 时发生错误:{errorMessage}",
+    "savedObjectsManagement.managementSectionLabel": "已保存对象",
+    "savedObjectsManagement.view.cancelButtonAriaLabel": "取消",
+    "savedObjectsManagement.view.cancelButtonLabel": "取消",
+    "savedObjectsManagement.view.deleteItemButtonLabel": "删除“{title}”",
+    "savedObjectsManagement.view.editItemTitle": "编辑“{title}",
+    "savedObjectsManagement.view.fieldDoesNotExistErrorMessage": "与此对象关联的字段在该索引模式中已不存在。",
+    "savedObjectsManagement.view.howToFixErrorDescription": "如果您清楚此错误的含义,请修复该错误 — 否则单击上面的删除按钮。",
+    "savedObjectsManagement.view.howToModifyObjectDescription": " 修改对象仅适用于高级用户。对象属性未得到验证,无效的对象可能会导致错误、数据丢失或更坏的情况发生。除非熟悉该代码的人让您来这里,否则您可能不应该来这里。",
+    "savedObjectsManagement.view.howToModifyObjectTitle": "谨慎操作!",
+    "savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "与此对象关联的索引模式已不存在。",
+    "savedObjectsManagement.view.saveButtonAriaLabel": "保存 { title } 对象",
+    "savedObjectsManagement.view.saveButtonLabel": "保存 { title } 对象",
+    "savedObjectsManagement.view.savedObjectProblemErrorMessage": "此已保存对象有问题",
+    "savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "与此对象关联的已保存搜索已不存在。",
+    "savedObjectsManagement.view.viewItemButtonLabel": "查看“{title}”",
+    "savedObjectsManagement.view.viewItemTitle": "查看“{title}”",
+    "savedObjectsManagement.breadcrumb.edit": "编辑 {savedObjectType}",
+    "savedObjectsManagement.breadcrumb.index": "已保存对象",
     "kbn.managementTitle": "管理",
     "kbn.topNavMenu.openInspectorButtonLabel": "检查",
     "kbn.topNavMenu.refreshButtonLabel": "刷新",

From 61271c0652a8393f9af6972a46b31759d8b81c7d Mon Sep 17 00:00:00 2001
From: Shahzad <shahzad.muhammad@elastic.co>
Date: Mon, 13 Apr 2020 13:44:10 +0200
Subject: [PATCH 71/78] [Uptime] Simplify monitor param usage (#63121)

* add useMonitorId hook

* update url param hook

* update type

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../connected/charts/monitor_duration.tsx     |  5 ++--
 .../connected/charts/ping_histogram.tsx       |  5 ++--
 .../connected/charts/snapshot_container.tsx   |  5 ++--
 .../monitor/list_drawer_container.tsx         |  5 ++--
 .../monitor/status_bar_container.tsx          |  5 ++--
 .../monitor/status_details_container.tsx      |  5 ++--
 .../monitor_list_drawer/most_recent_error.tsx |  5 ++--
 .../monitor_details/ml/manage_ml_job.tsx      | 10 +++----
 .../ml/ml_flyout_container.tsx                | 10 +++----
 .../monitor_details/ml/ml_integeration.tsx    |  6 ++---
 .../contexts/uptime_settings_context.tsx      |  6 ++---
 .../hooks/__tests__/use_url_params.test.tsx   |  3 ++-
 .../uptime/public/hooks/use_monitor.ts        | 14 ++++++++++
 .../uptime/public/hooks/use_telemetry.ts      | 10 ++++---
 .../uptime/public/hooks/use_url_params.ts     | 27 +++++++++----------
 .../plugins/uptime/public/pages/monitor.tsx   |  6 ++---
 .../plugins/uptime/public/pages/overview.tsx  |  5 ++--
 17 files changed, 66 insertions(+), 66 deletions(-)
 create mode 100644 x-pack/legacy/plugins/uptime/public/hooks/use_monitor.ts

diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/monitor_duration.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/monitor_duration.tsx
index 7d1cb08cb8b1c..40480905350af 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/charts/monitor_duration.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/monitor_duration.tsx
@@ -6,7 +6,7 @@
 
 import React, { useContext, useEffect } from 'react';
 import { useDispatch, useSelector } from 'react-redux';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 import {
   getAnomalyRecordsAction,
   getMLCapabilitiesAction,
@@ -28,13 +28,12 @@ interface Props {
 }
 
 export const DurationChart: React.FC<Props> = ({ monitorId }: Props) => {
-  const [getUrlParams] = useUrlParams();
   const {
     dateRangeStart,
     dateRangeEnd,
     absoluteDateRangeStart,
     absoluteDateRangeEnd,
-  } = getUrlParams();
+  } = useGetUrlParams();
 
   const { durationLines, loading } = useSelector(selectDurationLines);
 
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx
index 50f91be4ff09f..6428ddfd10f8c 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx
@@ -15,7 +15,7 @@ import { getPingHistogram } from '../../../state/actions';
 import { selectPingHistogram } from '../../../state/selectors';
 import { withResponsiveWrapper, ResponsiveWrapperProps } from '../../higher_order';
 import { GetPingHistogramParams, HistogramResult } from '../../../../common/types';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 
 type Props = ResponsiveWrapperProps &
   Pick<PingHistogramComponentProps, 'height' | 'data' | 'loading'> &
@@ -30,14 +30,13 @@ const PingHistogramContainer: React.FC<Props> = ({
   loading,
   esKuery,
 }) => {
-  const [getUrlParams] = useUrlParams();
   const {
     absoluteDateRangeStart,
     absoluteDateRangeEnd,
     dateRangeStart: dateStart,
     dateRangeEnd: dateEnd,
     statusFilter,
-  } = getUrlParams();
+  } = useGetUrlParams();
 
   useEffect(() => {
     loadData({ monitorId, dateStart, dateEnd, statusFilter, filters: esKuery });
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx
index ac8ff13d1edce..39ead242527f8 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx
@@ -6,7 +6,7 @@
 
 import React, { useEffect } from 'react';
 import { connect } from 'react-redux';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 import { AppState } from '../../../state';
 import { getSnapshotCountAction } from '../../../state/actions';
 import { SnapshotComponent } from '../../functional/snapshot';
@@ -54,8 +54,7 @@ export const Container: React.FC<Props> = ({
   esKuery,
   loadSnapshotCount,
 }: Props) => {
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart, dateRangeEnd, statusFilter } = getUrlParams();
+  const { dateRangeStart, dateRangeEnd, statusFilter } = useGetUrlParams();
 
   useEffect(() => {
     loadSnapshotCount({ dateRangeStart, dateRangeEnd, filters: esKuery, statusFilter });
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx
index ceeaa7026059f..70da62d5833af 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx
@@ -11,7 +11,7 @@ import { monitorDetailsSelector } from '../../../state/selectors';
 import { MonitorDetailsActionPayload } from '../../../state/actions/types';
 import { getMonitorDetailsAction } from '../../../state/actions/monitor';
 import { MonitorListDrawerComponent } from '../../functional/monitor_list/monitor_list_drawer/monitor_list_drawer';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 import { MonitorSummary } from '../../../../common/graphql/types';
 import { MonitorDetails } from '../../../../common/runtime_types/monitor';
 
@@ -24,8 +24,7 @@ interface ContainerProps {
 const Container: React.FC<ContainerProps> = ({ summary, loadMonitorDetails, monitorDetails }) => {
   const monitorId = summary?.monitor_id;
 
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams();
+  const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = useGetUrlParams();
 
   useEffect(() => {
     loadMonitorDetails({
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx
index dd6f7a89cf9a3..00cfd02d8dc32 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx
@@ -11,7 +11,7 @@ import { AppState } from '../../../state';
 import { monitorLocationsSelector, monitorStatusSelector } from '../../../state/selectors';
 import { MonitorStatusBarComponent } from '../../functional/monitor_status_details/monitor_status_bar';
 import { getMonitorStatusAction } from '../../../state/actions';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 import { Ping } from '../../../../common/graphql/types';
 import { MonitorLocations } from '../../../../common/runtime_types/monitor';
 import { UptimeRefreshContext } from '../../../contexts';
@@ -39,8 +39,7 @@ const Container: React.FC<Props> = ({
 }: Props) => {
   const { lastRefresh } = useContext(UptimeRefreshContext);
 
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams();
+  const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = useGetUrlParams();
 
   useEffect(() => {
     loadMonitorStatus({ dateStart, dateEnd, monitorId });
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx
index 3ced251dfab8c..9d2e48830fbfe 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx
@@ -7,7 +7,7 @@
 import React, { useContext, useEffect } from 'react';
 import { connect } from 'react-redux';
 import { Dispatch } from 'redux';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 import { AppState } from '../../../state';
 import { monitorLocationsSelector } from '../../../state/selectors';
 import { getMonitorLocationsAction, MonitorLocationsPayload } from '../../../state/actions/monitor';
@@ -36,8 +36,7 @@ export const Container: React.FC<Props> = ({
 }: Props) => {
   const { lastRefresh } = useContext(UptimeRefreshContext);
 
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams();
+  const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = useGetUrlParams();
 
   useEffect(() => {
     loadMonitorLocations({ dateStart, dateEnd, monitorId });
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/most_recent_error.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/most_recent_error.tsx
index 036882b49359f..1963a9c852b11 100644
--- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/most_recent_error.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/most_recent_error.tsx
@@ -8,7 +8,7 @@ import { EuiText, EuiSpacer } from '@elastic/eui';
 import moment from 'moment';
 import { i18n } from '@kbn/i18n';
 import { MonitorPageLink } from '../monitor_page_link';
-import { useUrlParams } from '../../../../hooks';
+import { useGetUrlParams } from '../../../../hooks';
 import { stringifyUrlParams } from '../../../../lib/helper/stringify_url_params';
 import { MonitorError } from '../../../../../common/runtime_types';
 
@@ -30,8 +30,7 @@ interface MostRecentErrorProps {
 }
 
 export const MostRecentError = ({ error, monitorId, timestamp }: MostRecentErrorProps) => {
-  const [getUrlParams] = useUrlParams();
-  const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams();
+  const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = useGetUrlParams();
   params.selectedPingStatus = 'down';
   const linkParameters = stringifyUrlParams(params, true);
 
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx
index 29f003437f7cb..1abda87abf73a 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx
@@ -7,13 +7,13 @@
 import React, { useContext, useState } from 'react';
 
 import { EuiButtonEmpty, EuiContextMenu, EuiIcon, EuiPopover } from '@elastic/eui';
-import { useParams } from 'react-router-dom';
 import { useSelector } from 'react-redux';
 import { canDeleteMLJobSelector } from '../../../state/selectors';
 import { UptimeSettingsContext } from '../../../contexts';
 import * as labels from './translations';
 import { getMLJobLinkHref } from './ml_job_link';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
+import { useMonitorId } from '../../../hooks/use_monitor';
 
 interface Props {
   hasMLJob: boolean;
@@ -28,11 +28,9 @@ export const ManageMLJobComponent = ({ hasMLJob, onEnableJob, onJobDelete }: Pro
 
   const canDeleteMLJob = useSelector(canDeleteMLJobSelector);
 
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart, dateRangeEnd } = getUrlParams();
+  const { dateRangeStart, dateRangeEnd } = useGetUrlParams();
 
-  let { monitorId } = useParams();
-  monitorId = atob(monitorId || '');
+  const monitorId = useMonitorId();
 
   const button = (
     <EuiButtonEmpty
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx
index 9eed24e2810d8..6953618d92213 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx
@@ -6,7 +6,6 @@
 
 import React, { useContext, useEffect, useState } from 'react';
 import { useDispatch, useSelector } from 'react-redux';
-import { useParams } from 'react-router-dom';
 import {
   canCreateMLJobSelector,
   hasMLJobSelector,
@@ -24,8 +23,9 @@ import {
 import { MLFlyoutView } from './ml_flyout';
 import { ML_JOB_ID } from '../../../../common/constants';
 import { UptimeRefreshContext, UptimeSettingsContext } from '../../../contexts';
-import { useUrlParams } from '../../../hooks';
+import { useGetUrlParams } from '../../../hooks';
 import { getDynamicSettings } from '../../../state/actions/dynamic_settings';
+import { useMonitorId } from '../../../hooks/use_monitor';
 
 interface Props {
   onClose: () => void;
@@ -77,8 +77,7 @@ export const MachineLearningFlyout: React.FC<Props> = ({ onClose }) => {
 
   const { refreshApp } = useContext(UptimeRefreshContext);
 
-  let { monitorId } = useParams();
-  monitorId = atob(monitorId || '');
+  const monitorId = useMonitorId();
 
   const canCreateMLJob = useSelector(canCreateMLJobSelector) && heartbeatIndices !== '';
 
@@ -93,8 +92,7 @@ export const MachineLearningFlyout: React.FC<Props> = ({ onClose }) => {
 
   const [isCreatingJob, setIsCreatingJob] = useState(false);
 
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart, dateRangeEnd } = getUrlParams();
+  const { dateRangeStart, dateRangeEnd } = useGetUrlParams();
 
   useEffect(() => {
     if (isCreatingJob && !isMLJobCreating) {
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx
index a27796167091e..e65a2510ea6f2 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx
@@ -5,8 +5,6 @@
  */
 
 import React, { useContext, useEffect, useState } from 'react';
-
-import { useParams } from 'react-router-dom';
 import { useDispatch, useSelector } from 'react-redux';
 import { MachineLearningFlyout } from './ml_flyout_container';
 import {
@@ -23,6 +21,7 @@ import * as labels from './translations';
 import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
 import { ManageMLJobComponent } from './manage_ml_job';
 import { JobStat } from '../../../../../../../plugins/ml/common/types/data_recognizer';
+import { useMonitorId } from '../../../hooks/use_monitor';
 
 export const MLIntegrationComponent = () => {
   const [isMlFlyoutOpen, setIsMlFlyoutOpen] = useState(false);
@@ -32,8 +31,7 @@ export const MLIntegrationComponent = () => {
 
   const { notifications } = useKibana();
 
-  let { monitorId } = useParams();
-  monitorId = atob(monitorId || '');
+  const monitorId = useMonitorId();
 
   const dispatch = useDispatch();
 
diff --git a/x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx b/x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx
index 44a87d310c9c7..c5a0ec4831798 100644
--- a/x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx
+++ b/x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx
@@ -8,7 +8,7 @@ import React, { createContext, useMemo } from 'react';
 import { UptimeAppProps } from '../uptime_app';
 import { CLIENT_DEFAULTS, CONTEXT_DEFAULTS } from '../../common/constants';
 import { CommonlyUsedRange } from '../components/functional/uptime_date_picker';
-import { useUrlParams } from '../hooks';
+import { useGetUrlParams } from '../hooks';
 import { ILicense } from '../../../../../plugins/licensing/common/types';
 
 export interface UptimeSettingsContextValues {
@@ -50,9 +50,7 @@ export const UptimeSettingsContextProvider: React.FC<UptimeAppProps> = ({ childr
     plugins,
   } = props;
 
-  const [getUrlParams] = useUrlParams();
-
-  const { dateRangeStart, dateRangeEnd } = getUrlParams();
+  const { dateRangeStart, dateRangeEnd } = useGetUrlParams();
 
   let license: ILicense | null = null;
 
diff --git a/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx b/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx
index a8999a50927d2..deb1f163c1326 100644
--- a/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx
+++ b/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx
@@ -19,6 +19,7 @@ interface MockUrlParamsComponentProps {
 const UseUrlParamsTestComponent = ({ hook, updateParams }: MockUrlParamsComponentProps) => {
   const [params, setParams] = useState({});
   const [getUrlParams, updateUrlParams] = hook();
+  const queryParams = getUrlParams();
   return (
     <Fragment>
       {Object.keys(params).length > 0 ? <div>{JSON.stringify(params)}</div> : null}
@@ -30,7 +31,7 @@ const UseUrlParamsTestComponent = ({ hook, updateParams }: MockUrlParamsComponen
       >
         Set url params
       </button>
-      <button id="getUrlParams" onClick={() => setParams(getUrlParams())}>
+      <button id="getUrlParams" onClick={() => setParams(queryParams)}>
         Get url params
       </button>
     </Fragment>
diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_monitor.ts b/x-pack/legacy/plugins/uptime/public/hooks/use_monitor.ts
new file mode 100644
index 0000000000000..8080ce2696a3c
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/hooks/use_monitor.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { useParams } from 'react-router-dom';
+
+export const useMonitorId = (): string => {
+  const { monitorId } = useParams();
+
+  // decode 64 base string, it was decoded to make it a valid url, since monitor id can be a url
+  return atob(monitorId || '');
+};
diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts b/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts
index 13fe523332ae5..a2012b8ac5636 100644
--- a/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts
+++ b/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts
@@ -5,7 +5,7 @@
  */
 
 import { useEffect } from 'react';
-import { useUrlParams } from './use_url_params';
+import { useGetUrlParams } from './use_url_params';
 import { apiService } from '../state/api/utils';
 import { API_URLS } from '../../common/constants';
 
@@ -17,8 +17,12 @@ export enum UptimePage {
 }
 
 export const useUptimeTelemetry = (page?: UptimePage) => {
-  const [getUrlParams] = useUrlParams();
-  const { dateRangeStart, dateRangeEnd, autorefreshInterval, autorefreshIsPaused } = getUrlParams();
+  const {
+    dateRangeStart,
+    dateRangeEnd,
+    autorefreshInterval,
+    autorefreshIsPaused,
+  } = useGetUrlParams();
 
   useEffect(() => {
     if (!apiService.http) throw new Error('Core http services are not defined');
diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_url_params.ts b/x-pack/legacy/plugins/uptime/public/hooks/use_url_params.ts
index 20063b2c1bc93..8b13e9e480559 100644
--- a/x-pack/legacy/plugins/uptime/public/hooks/use_url_params.ts
+++ b/x-pack/legacy/plugins/uptime/public/hooks/use_url_params.ts
@@ -15,27 +15,26 @@ export type UpdateUrlParams = (updatedParams: {
 
 export type UptimeUrlParamsHook = () => [GetUrlParams, UpdateUrlParams];
 
-export const useUrlParams: UptimeUrlParamsHook = () => {
+const getParsedParams = (search: string) => {
+  return search ? parse(search[0] === '?' ? search.slice(1) : search, { sort: false }) : {};
+};
+
+export const useGetUrlParams: GetUrlParams = () => {
   const location = useLocation();
-  const history = useHistory();
 
-  const getUrlParams: GetUrlParams = () => {
-    let search: string | undefined;
-    if (location) {
-      search = location.search;
-    }
+  const params = getParsedParams(location?.search);
 
-    const params = search
-      ? parse(search[0] === '?' ? search.slice(1) : search, { sort: false })
-      : {};
+  return getSupportedUrlParams(params);
+};
 
-    return getSupportedUrlParams(params);
-  };
+export const useUrlParams: UptimeUrlParamsHook = () => {
+  const location = useLocation();
+  const history = useHistory();
 
   const updateUrlParams: UpdateUrlParams = updatedParams => {
     if (!history || !location) return;
     const { pathname, search } = location;
-    const currentParams = parse(search[0] === '?' ? search.slice(1) : search, { sort: false });
+    const currentParams = getParsedParams(search);
     const mergedParams = {
       ...currentParams,
       ...updatedParams,
@@ -60,5 +59,5 @@ export const useUrlParams: UptimeUrlParamsHook = () => {
     });
   };
 
-  return [getUrlParams, updateUrlParams];
+  return [useGetUrlParams, updateUrlParams];
 };
diff --git a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx
index 21124b7323d68..5016ccebbab54 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx
@@ -6,7 +6,6 @@
 
 import { EuiSpacer } from '@elastic/eui';
 import React, { useContext, useState } from 'react';
-import { useParams } from 'react-router-dom';
 import { useSelector } from 'react-redux';
 import { MonitorCharts, PingList } from '../components/functional';
 import { UptimeRefreshContext } from '../contexts';
@@ -16,11 +15,10 @@ import { MonitorStatusDetails } from '../components/connected';
 import { monitorStatusSelector } from '../state/selectors';
 import { PageHeader } from './page_header';
 import { useBreadcrumbs } from '../hooks/use_breadcrumbs';
+import { useMonitorId } from '../hooks/use_monitor';
 
 export const MonitorPage: React.FC = () => {
-  // decode 64 base string, it was decoded to make it a valid url, since monitor id can be a url
-  let { monitorId } = useParams();
-  monitorId = atob(monitorId || '');
+  const monitorId = useMonitorId();
 
   const [pingListPageCount, setPingListPageCount] = useState<number>(10);
   const { refreshApp } = useContext(UptimeRefreshContext);
diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx
index 943dbd6bd57ba..5550facaf42e9 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx
@@ -13,7 +13,7 @@ import {
   OverviewPageParsingErrorCallout,
   StatusPanel,
 } from '../components/functional';
-import { useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks';
+import { useUptimeTelemetry, UptimePage, useGetUrlParams } from '../hooks';
 import { stringifyUrlParams } from '../lib/helper/stringify_url_params';
 import { useTrackPageview } from '../../../../../plugins/observability/public';
 import { DataPublicPluginSetup, IIndexPattern } from '../../../../../../src/plugins/data/public';
@@ -55,12 +55,11 @@ const getMonitorListPageSizeValue = () => {
 
 export const OverviewPageComponent = ({ autocomplete, indexPattern, setEsKueryFilters }: Props) => {
   const { colors } = useContext(UptimeThemeContext);
-  const [getUrlParams] = useUrlParams();
   // TODO: this is temporary until we migrate the monitor list to our Redux implementation
   const [monitorListPageSize, setMonitorListPageSize] = useState<number>(
     getMonitorListPageSizeValue()
   );
-  const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams();
+  const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = useGetUrlParams();
   const {
     dateRangeStart,
     dateRangeEnd,

From c7f61f956a581bf39be01f9e0c263577c2165b6b Mon Sep 17 00:00:00 2001
From: Shahzad <shahzad.muhammad@elastic.co>
Date: Mon, 13 Apr 2020 13:49:46 +0200
Subject: [PATCH 72/78] [Uptime] Update Ml functional test (#62562)

* update test

* added test

* updated type

* updated test

* updated test

* update test

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../connected/empty_state/empty_state.tsx     |  6 +-
 .../confirm_delete.test.tsx.snap              |  2 +
 .../__snapshots__/license_info.test.tsx.snap  |  2 +
 .../__snapshots__/ml_flyout.test.tsx.snap     |  5 ++
 .../ml_integerations.test.tsx.snap            |  1 +
 .../__snapshots__/ml_manage_job.test.tsx.snap |  1 +
 .../monitor_details/ml/confirm_delete.tsx     |  1 +
 .../monitor_details/ml/license_info.tsx       |  1 +
 .../monitor_details/ml/manage_ml_job.tsx      |  8 ++-
 .../monitor_details/ml/ml_flyout.tsx          |  3 +-
 .../ml/ml_flyout_container.tsx                |  6 +-
 .../monitor_details/ml/ml_integeration.tsx    |  2 +-
 .../plugins/uptime/public/pages/settings.tsx  |  2 +-
 x-pack/test/functional/apps/uptime/index.ts   |  5 +-
 .../test/functional/apps/uptime/ml_anomaly.ts | 51 ++++++++++++++++
 x-pack/test/functional/apps/uptime/monitor.ts |  7 +--
 .../test/functional/apps/uptime/overview.ts   | 24 ++++----
 .../functional/page_objects/uptime_page.ts    | 39 ++++++------
 .../test/functional/services/uptime/common.ts | 15 +++++
 .../functional/services/uptime/ml_anomaly.ts  | 59 +++++++++++++++++++
 .../functional/services/uptime/navigation.ts  | 52 +++++++++++-----
 .../test/functional/services/uptime/uptime.ts |  3 +
 22 files changed, 235 insertions(+), 60 deletions(-)
 create mode 100644 x-pack/test/functional/apps/uptime/ml_anomaly.ts
 create mode 100644 x-pack/test/functional/services/uptime/ml_anomaly.ts

diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/empty_state/empty_state.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/empty_state/empty_state.tsx
index b383a696095a3..55c92e70b6066 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/empty_state/empty_state.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/empty_state/empty_state.tsx
@@ -4,20 +4,22 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import React, { useEffect } from 'react';
+import React, { useContext, useEffect } from 'react';
 import { useDispatch, useSelector } from 'react-redux';
 import { indexStatusAction } from '../../../state/actions';
 import { indexStatusSelector } from '../../../state/selectors';
 import { EmptyStateComponent } from '../../functional/empty_state/empty_state';
+import { UptimeRefreshContext } from '../../../contexts';
 
 export const EmptyState: React.FC = ({ children }) => {
   const { data, loading, error } = useSelector(indexStatusSelector);
+  const { lastRefresh } = useContext(UptimeRefreshContext);
 
   const dispatch = useDispatch();
 
   useEffect(() => {
     dispatch(indexStatusAction.get());
-  }, [dispatch]);
+  }, [dispatch, lastRefresh]);
 
   return (
     <EmptyStateComponent
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap
index 24ef7eda0d129..d83e45fea1aec 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap
@@ -6,6 +6,7 @@ exports[`ML Confirm Job Delete shallow renders without errors 1`] = `
     buttonColor="danger"
     cancelButtonText="Cancel"
     confirmButtonText="Delete"
+    data-test-subj="uptimeMLJobDeleteConfirmModel"
     defaultFocusedButton="confirm"
     onCancel={[MockFunction]}
     onConfirm={[MockFunction]}
@@ -35,6 +36,7 @@ exports[`ML Confirm Job Delete shallow renders without errors while loading 1`]
     buttonColor="danger"
     cancelButtonText="Cancel"
     confirmButtonText="Delete"
+    data-test-subj="uptimeMLJobDeleteConfirmModel"
     defaultFocusedButton="confirm"
     onCancel={[MockFunction]}
     onConfirm={[MockFunction]}
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/license_info.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/license_info.test.tsx.snap
index 2457488c4facc..fb40a42e47f75 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/license_info.test.tsx.snap
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/license_info.test.tsx.snap
@@ -4,6 +4,7 @@ exports[`ShowLicenseInfo renders without errors 1`] = `
 Array [
   <div
     class="euiCallOut euiCallOut--primary license-info-trial"
+    data-test-subj="uptimeMLLicenseInfo"
   >
     <div
       class="euiCallOutHeader"
@@ -54,6 +55,7 @@ exports[`ShowLicenseInfo shallow renders without errors 1`] = `
   <EuiCallOut
     className="license-info-trial"
     color="primary"
+    data-test-subj="uptimeMLLicenseInfo"
     iconType="help"
     title="Start free 14-day trial"
   >
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap
index ead27425c26f3..a83a1d99d7bb0 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap
@@ -3,6 +3,7 @@
 exports[`ML Flyout component renders without errors 1`] = `
 <EuiFlyout
   closeButtonAriaLabel="Closes this dialog"
+  data-test-subj="uptimeMLFlyout"
   hideCloseButton={false}
   maxWidth={false}
   onClose={[Function]}
@@ -69,6 +70,7 @@ exports[`ML Flyout component renders without errors 1`] = `
         grow={false}
       >
         <EuiButton
+          data-test-subj="uptimeMLCreateJobBtn"
           disabled={true}
           fill={true}
           isLoading={false}
@@ -99,6 +101,7 @@ exports[`ML Flyout component shows license info if no ml available 1`] = `
   >
     <div
       class="euiFlyout euiFlyout--small"
+      data-test-subj="uptimeMLFlyout"
       role="dialog"
       tabindex="0"
     >
@@ -137,6 +140,7 @@ exports[`ML Flyout component shows license info if no ml available 1`] = `
           >
             <div
               class="euiCallOut euiCallOut--primary license-info-trial"
+              data-test-subj="uptimeMLLicenseInfo"
             >
               <div
                 class="euiCallOutHeader"
@@ -240,6 +244,7 @@ exports[`ML Flyout component shows license info if no ml available 1`] = `
           >
             <button
               class="euiButton euiButton--primary euiButton--fill"
+              data-test-subj="uptimeMLCreateJobBtn"
               disabled=""
               type="button"
             >
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap
index ac4630f4e69a8..fa9b59e13c34e 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap
@@ -9,6 +9,7 @@ exports[`ML Integrations renders without errors 1`] = `
   >
     <button
       class="euiButtonEmpty euiButtonEmpty--primary"
+      data-test-subj="uptimeEnableAnomalyBtn"
       type="button"
     >
       <span
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap
index 6eb2930c4875a..91bd9fa3d86b5 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap
@@ -9,6 +9,7 @@ exports[`Manage ML Job renders without errors 1`] = `
   >
     <button
       class="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--iconRight"
+      data-test-subj="uptimeManageMLJobBtn"
       type="button"
     >
       <span
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/confirm_delete.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/confirm_delete.tsx
index 6754676765fb6..628f943ef2e08 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/confirm_delete.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/confirm_delete.tsx
@@ -25,6 +25,7 @@ export const ConfirmJobDeletion: React.FC<Props> = ({ loading, onConfirm, onCanc
         confirmButtonText="Delete"
         buttonColor="danger"
         defaultFocusedButton="confirm"
+        data-test-subj="uptimeMLJobDeleteConfirmModel"
       >
         {!loading ? (
           <p>
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/license_info.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/license_info.tsx
index 92badb4043ed6..fae81177a728c 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/license_info.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/license_info.tsx
@@ -13,6 +13,7 @@ export const ShowLicenseInfo = () => {
   return (
     <>
       <EuiCallOut
+        data-test-subj="uptimeMLLicenseInfo"
         className="license-info-trial"
         title={labels.START_TRAIL}
         color="primary"
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx
index 1abda87abf73a..ec3e8bb2b9f68 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/manage_ml_job.tsx
@@ -34,6 +34,7 @@ export const ManageMLJobComponent = ({ hasMLJob, onEnableJob, onJobDelete }: Pro
 
   const button = (
     <EuiButtonEmpty
+      data-test-subj={hasMLJob ? 'uptimeManageMLJobBtn' : 'uptimeEnableAnomalyBtn'}
       iconType={hasMLJob ? 'arrowDown' : 'machineLearningApp'}
       iconSide={hasMLJob ? 'right' : 'left'}
       onClick={hasMLJob ? () => setIsPopOverOpen(true) : onEnableJob}
@@ -60,6 +61,7 @@ export const ManageMLJobComponent = ({ hasMLJob, onEnableJob, onJobDelete }: Pro
         },
         {
           name: labels.DISABLE_ANOMALY_DETECTION,
+          'data-test-subj': 'uptimeDeleteMLJobBtn',
           icon: <EuiIcon type="trash" size="m" />,
           onClick: () => {
             setIsPopOverOpen(false);
@@ -72,7 +74,11 @@ export const ManageMLJobComponent = ({ hasMLJob, onEnableJob, onJobDelete }: Pro
 
   return (
     <EuiPopover button={button} isOpen={isPopOverOpen} closePopover={() => setIsPopOverOpen(false)}>
-      <EuiContextMenu initialPanelId={0} panels={panels} />
+      <EuiContextMenu
+        initialPanelId={0}
+        panels={panels}
+        data-test-subj="uptimeManageMLContextMenu"
+      />
     </EuiPopover>
   );
 };
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout.tsx
index fdecfbf20810c..8c3f814e841f7 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout.tsx
@@ -39,7 +39,7 @@ export function MLFlyoutView({ isCreatingJob, onClickCreate, onClose, canCreateM
   const hasPlatinumLicense = license?.getFeature('ml')?.isAvailable;
 
   return (
-    <EuiFlyout onClose={onClose} size="s">
+    <EuiFlyout onClose={onClose} size="s" data-test-subj="uptimeMLFlyout">
       <EuiFlyoutHeader>
         <EuiTitle>
           <h2>{labels.ENABLE_ANOMALY_DETECTION}</h2>
@@ -76,6 +76,7 @@ export function MLFlyoutView({ isCreatingJob, onClickCreate, onClose, canCreateM
           </EuiFlexItem>
           <EuiFlexItem grow={false}>
             <EuiButton
+              data-test-subj="uptimeMLCreateJobBtn"
               onClick={() => onClickCreate()}
               fill
               isLoading={isCreatingJob}
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx
index 6953618d92213..a13de192cc443 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_flyout_container.tsx
@@ -41,7 +41,9 @@ const showMLJobNotification = (
 ) => {
   if (success) {
     notifications.toasts.success({
-      title: <p>{labels.JOB_CREATED_SUCCESS_TITLE}</p>,
+      title: (
+        <p data-test-subj="uptimeMLJobSuccessfullyCreated">{labels.JOB_CREATED_SUCCESS_TITLE}</p>
+      ),
       body: (
         <p>
           {labels.JOB_CREATED_SUCCESS_MESSAGE}
@@ -54,7 +56,7 @@ const showMLJobNotification = (
     });
   } else {
     notifications.toasts.danger({
-      title: <p>{labels.JOB_CREATION_FAILED}</p>,
+      title: <p data-test-subj="uptimeMLJobCreationFailed">{labels.JOB_CREATION_FAILED}</p>,
       body: message ?? <p>{labels.JOB_CREATION_FAILED_MESSAGE}</p>,
       toastLifeTimeMs: 10000,
     });
diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx
index e65a2510ea6f2..e053ca733cb8c 100644
--- a/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/monitor_details/ml/ml_integeration.tsx
@@ -57,7 +57,7 @@ export const MLIntegrationComponent = () => {
     if (isConfirmDeleteJobOpen && jobDeletionSuccess?.[getMLJobId(monitorId as string)]?.deleted) {
       setIsConfirmDeleteJobOpen(false);
       notifications.toasts.success({
-        title: <p>{labels.JOB_DELETION}</p>,
+        title: <p data-test-subj="uptimeMLJobSuccessfullyDeleted">{labels.JOB_DELETION}</p>,
         body: <p>{labels.JOB_DELETION_SUCCESS}</p>,
         toastLifeTimeMs: 3000,
       });
diff --git a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
index d3e17a15ee0e0..765b0e3c664bc 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
@@ -112,7 +112,7 @@ export const SettingsPageComponent = ({
 
   return (
     <>
-      <Link to={OVERVIEW_ROUTE}>
+      <Link to={OVERVIEW_ROUTE} data-test-subj="uptimeSettingsToOverviewLink">
         <EuiButtonEmpty size="s" color="primary" iconType="arrowLeft">
           {i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', {
             defaultMessage: 'Return to overview',
diff --git a/x-pack/test/functional/apps/uptime/index.ts b/x-pack/test/functional/apps/uptime/index.ts
index 3789351263b98..f47214dc2ad2f 100644
--- a/x-pack/test/functional/apps/uptime/index.ts
+++ b/x-pack/test/functional/apps/uptime/index.ts
@@ -16,6 +16,7 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => {
   const esArchiver = getService('esArchiver');
   const kibanaServer = getService('kibanaServer');
   const server = getService('kibanaServer');
+  const uptime = getService('uptime');
 
   describe('Uptime app', function() {
     this.tags('ciGroup6');
@@ -58,12 +59,14 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => {
         await esArchiver.unload(ARCHIVE);
         await esArchiver.load(ARCHIVE);
         await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'UTC' });
+        await uptime.navigation.goToUptime();
       });
       after(async () => await esArchiver.unload(ARCHIVE));
 
-      loadTestFile(require.resolve('./feature_controls'));
       loadTestFile(require.resolve('./overview'));
       loadTestFile(require.resolve('./monitor'));
+      loadTestFile(require.resolve('./ml_anomaly'));
+      loadTestFile(require.resolve('./feature_controls'));
     });
   });
 };
diff --git a/x-pack/test/functional/apps/uptime/ml_anomaly.ts b/x-pack/test/functional/apps/uptime/ml_anomaly.ts
new file mode 100644
index 0000000000000..bcd165cc1afb7
--- /dev/null
+++ b/x-pack/test/functional/apps/uptime/ml_anomaly.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../ftr_provider_context';
+
+export default ({ getService }: FtrProviderContext) => {
+  const uptime = getService('uptime');
+  const log = getService('log');
+
+  describe('uptime ml anomaly', function() {
+    this.tags(['skipFirefox']);
+    const dateStart = 'Sep 10, 2019 @ 12:40:08.078';
+    const dateEnd = 'Sep 11, 2019 @ 19:40:08.078';
+    const monitorId = '0000-intermittent';
+
+    before(async () => {
+      if (!(await uptime.navigation.checkIfOnMonitorPage(monitorId))) {
+        await uptime.navigation.loadDataAndGoToMonitorPage(dateStart, dateEnd, monitorId);
+      }
+      if (await uptime.ml.alreadyHasJob()) {
+        log.info('Jon already exists so lets delete it to start fresh.');
+        await uptime.ml.deleteMLJob();
+      }
+    });
+
+    it('can open ml flyout', async () => {
+      await uptime.ml.openMLFlyout();
+    });
+
+    it('has permission to  create job', async () => {
+      expect(uptime.ml.canCreateJob()).to.eql(true);
+      expect(uptime.ml.hasNoLicenseInfo()).to.eql(false);
+    });
+
+    it('can create job successfully', async () => {
+      await uptime.ml.createMLJob();
+      // await uptime.navigation.refreshApp();
+    });
+
+    it('can open ML Manage Menu', async () => {
+      await uptime.ml.openMLManageMenu();
+    });
+
+    it('can delete job successfully', async () => {
+      await uptime.ml.deleteMLJob();
+    });
+  });
+};
diff --git a/x-pack/test/functional/apps/uptime/monitor.ts b/x-pack/test/functional/apps/uptime/monitor.ts
index e15750eb6157b..90ad1836c69d3 100644
--- a/x-pack/test/functional/apps/uptime/monitor.ts
+++ b/x-pack/test/functional/apps/uptime/monitor.ts
@@ -17,19 +17,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
     const dateStart = 'Sep 10, 2019 @ 12:40:08.078';
     const dateEnd = 'Sep 11, 2019 @ 19:40:08.078';
     const monitorId = '0000-intermittent';
-    const monitorName = '0000-intermittent';
 
     before(async () => {
       await esArchiver.loadIfNeeded(archive);
       await uptimeService.navigation.goToUptime();
     });
 
-    after(async () => {
-      await esArchiver.unload(archive);
-    });
-
     it('loads and displays uptime data based on date range', async () => {
-      await uptime.loadDataAndGoToMonitorPage(dateStart, dateEnd, monitorId, monitorName);
+      await uptime.loadDataAndGoToMonitorPage(dateStart, dateEnd, monitorId);
     });
   });
 };
diff --git a/x-pack/test/functional/apps/uptime/overview.ts b/x-pack/test/functional/apps/uptime/overview.ts
index 8195e6bbb6035..d0dfca64634f6 100644
--- a/x-pack/test/functional/apps/uptime/overview.ts
+++ b/x-pack/test/functional/apps/uptime/overview.ts
@@ -14,6 +14,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
   describe('overview page', function() {
     const DEFAULT_DATE_START = 'Sep 10, 2019 @ 12:40:08.078';
     const DEFAULT_DATE_END = 'Sep 11, 2019 @ 19:40:08.078';
+
+    beforeEach(async () => {
+      await uptime.goToRoot();
+      await uptime.setDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
+      await uptime.resetFilters();
+    });
+
     it('loads and displays uptime data based on date range', async () => {
       await uptime.goToUptimeOverviewAndLoadData(
         DEFAULT_DATE_START,
@@ -22,13 +29,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
       );
     });
 
-    it('runs filter query without issues', async () => {
-      await uptime.inputFilterQuery('monitor.status:up and monitor.id:"0000-intermittent"');
-      await uptime.pageHasExpectedIds(['0000-intermittent']);
-    });
-
     it('applies filters for multiple fields', async () => {
-      await uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
       await uptime.selectFilterItems({
         location: ['mpls'],
         port: ['5678'],
@@ -49,7 +50,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
     });
 
     it('pagination is cleared when filter criteria changes', async () => {
-      await uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
       await uptime.changePage('next');
       await uptime.pageHasExpectedIds([
         '0010-down',
@@ -83,7 +83,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
     });
 
     it('clears pagination parameters when size changes', async () => {
-      await uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
       await uptime.changePage('next');
       await uptime.pageUrlContains('pagination');
       await uptime.setMonitorListPageSize(50);
@@ -92,7 +91,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
     });
 
     it('pagination size updates to reflect current selection', async () => {
-      await uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
       await uptime.pageHasExpectedIds([
         '0000-intermittent',
         '0001-up',
@@ -162,7 +160,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
 
     describe('snapshot counts', () => {
       it('updates the snapshot count when status filter is set to down', async () => {
-        await uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
         await uptime.setStatusFilter('down');
 
         await retry.tryForTime(12000, async () => {
@@ -172,13 +169,18 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
       });
 
       it('updates the snapshot count when status filter is set to up', async () => {
-        await uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
         await uptime.setStatusFilter('up');
         await retry.tryForTime(12000, async () => {
           const counts = await uptime.getSnapshotCount();
           expect(counts).to.eql({ up: '93', down: '0' });
         });
       });
+
+      it('runs filter query without issues', async () => {
+        await uptime.inputFilterQuery('monitor.status:up and monitor.id:"0000-intermittent"');
+        await uptime.pageHasExpectedIds(['0000-intermittent']);
+        await uptime.resetFilters();
+      });
     });
   });
 };
diff --git a/x-pack/test/functional/page_objects/uptime_page.ts b/x-pack/test/functional/page_objects/uptime_page.ts
index 39c3c46adddbb..7157bbfb3811b 100644
--- a/x-pack/test/functional/page_objects/uptime_page.ts
+++ b/x-pack/test/functional/page_objects/uptime_page.ts
@@ -14,37 +14,33 @@ export function UptimePageProvider({ getPageObjects, getService }: FtrProviderCo
 
   return new (class UptimePage {
     public async goToRoot() {
-      await pageObjects.common.navigateToApp('uptime');
+      await navigation.goToUptime();
     }
 
-    public async goToUptimePageAndSetDateRange(
-      datePickerStartValue: string,
-      datePickerEndValue: string
-    ) {
-      await pageObjects.common.navigateToApp('uptime');
-      await pageObjects.timePicker.setAbsoluteRange(datePickerStartValue, datePickerEndValue);
+    public async setDateRange(start: string, end: string) {
+      const { start: prevStart, end: prevEnd } = await pageObjects.timePicker.getTimeConfig();
+      if (start !== prevStart || prevEnd !== end) {
+        await pageObjects.timePicker.setAbsoluteRange(start, end);
+      } else {
+        await navigation.refreshApp();
+      }
     }
 
     public async goToUptimeOverviewAndLoadData(
-      datePickerStartValue: string,
-      datePickerEndValue: string,
+      dateStart: string,
+      dateEnd: string,
       monitorIdToCheck?: string
     ) {
-      await pageObjects.common.navigateToApp('uptime');
-      await pageObjects.timePicker.setAbsoluteRange(datePickerStartValue, datePickerEndValue);
+      await navigation.goToUptime();
+      await this.setDateRange(dateStart, dateEnd);
       if (monitorIdToCheck) {
         await commonService.monitorIdExists(monitorIdToCheck);
       }
     }
 
-    public async loadDataAndGoToMonitorPage(
-      datePickerStartValue: string,
-      datePickerEndValue: string,
-      monitorId: string,
-      monitorName?: string
-    ) {
-      await pageObjects.timePicker.setAbsoluteRange(datePickerStartValue, datePickerEndValue);
-      await navigation.goToMonitor(monitorId, monitorName);
+    public async loadDataAndGoToMonitorPage(dateStart: string, dateEnd: string, monitorId: string) {
+      await this.setDateRange(dateStart, dateEnd);
+      await navigation.goToMonitor(monitorId);
     }
 
     public async inputFilterQuery(filterQuery: string) {
@@ -140,5 +136,10 @@ export function UptimePageProvider({ getPageObjects, getService }: FtrProviderCo
       await commonService.openPageSizeSelectPopover();
       return commonService.clickPageSizeSelectPopoverItem(size);
     }
+
+    public async resetFilters() {
+      await this.inputFilterQuery('');
+      await commonService.resetStatusFilter();
+    }
   })();
 }
diff --git a/x-pack/test/functional/services/uptime/common.ts b/x-pack/test/functional/services/uptime/common.ts
index ed465eee343f9..b5be1e29a0e8c 100644
--- a/x-pack/test/functional/services/uptime/common.ts
+++ b/x-pack/test/functional/services/uptime/common.ts
@@ -10,6 +10,7 @@ export function UptimeCommonProvider({ getService }: FtrProviderContext) {
   const testSubjects = getService('testSubjects');
   const browser = getService('browser');
   const retry = getService('retry');
+  const find = getService('find');
 
   return {
     async assertExists(key: string) {
@@ -52,6 +53,20 @@ export function UptimeCommonProvider({ getService }: FtrProviderContext) {
     async setStatusFilterDown() {
       await testSubjects.click('xpack.uptime.filterBar.filterStatusDown');
     },
+    async resetStatusFilter() {
+      const upFilter = await find.byCssSelector(
+        '[data-test-subj="xpack.uptime.filterBar.filterStatusUp"]'
+      );
+      if (await upFilter.elementHasClass('euiFilterButton-hasActiveFilters')) {
+        this.setStatusFilterUp();
+      }
+      const downFilter = await find.byCssSelector(
+        '[data-test-subj="xpack.uptime.filterBar.filterStatusDown"]'
+      );
+      if (await downFilter.elementHasClass('euiFilterButton-hasActiveFilters')) {
+        this.setStatusFilterDown();
+      }
+    },
     async selectFilterItem(filterType: string, option: string) {
       const popoverId = `filter-popover_${filterType}`;
       const optionId = `filter-popover-item_${option}`;
diff --git a/x-pack/test/functional/services/uptime/ml_anomaly.ts b/x-pack/test/functional/services/uptime/ml_anomaly.ts
new file mode 100644
index 0000000000000..e15f47ddd9709
--- /dev/null
+++ b/x-pack/test/functional/services/uptime/ml_anomaly.ts
@@ -0,0 +1,59 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { FtrProviderContext } from '../../ftr_provider_context';
+
+export function UptimeMLAnomalyProvider({ getService }: FtrProviderContext) {
+  const testSubjects = getService('testSubjects');
+  const retry = getService('retry');
+  const log = getService('log');
+
+  return {
+    async openMLFlyout() {
+      return retry.tryForTime(15000, async () => {
+        await testSubjects.click('uptimeEnableAnomalyBtn');
+        await testSubjects.existOrFail('uptimeMLFlyout');
+      });
+    },
+
+    async openMLManageMenu() {
+      return retry.tryForTime(30000, async () => {
+        await testSubjects.click('uptimeManageMLJobBtn');
+        await testSubjects.existOrFail('uptimeManageMLContextMenu');
+      });
+    },
+
+    async alreadyHasJob() {
+      return await testSubjects.exists('uptimeManageMLJobBtn');
+    },
+
+    async createMLJob() {
+      await testSubjects.click('uptimeMLCreateJobBtn');
+      return retry.tryForTime(10000, async () => {
+        await testSubjects.existOrFail('uptimeMLJobSuccessfullyCreated');
+        log.info('Job successfully created');
+      });
+    },
+
+    async deleteMLJob() {
+      await testSubjects.click('uptimeDeleteMLJobBtn');
+      return retry.tryForTime(10000, async () => {
+        await testSubjects.click('uptimeMLJobDeleteConfirmModel > confirmModalConfirmButton');
+        await testSubjects.existOrFail('uptimeMLJobSuccessfullyDeleted');
+        log.info('Job successfully deleted');
+      });
+    },
+
+    async canCreateJob() {
+      const createJobBtn = await testSubjects.find('uptimeMLCreateJobBtn');
+      return !!(await createJobBtn.getAttribute('disabled'));
+    },
+
+    async hasNoLicenseInfo() {
+      return await testSubjects.missingOrFail('uptimeMLLicenseInfo', { timeout: 1000 });
+    },
+  };
+}
diff --git a/x-pack/test/functional/services/uptime/navigation.ts b/x-pack/test/functional/services/uptime/navigation.ts
index 15ee869da1e6a..36a5d7c9702f8 100644
--- a/x-pack/test/functional/services/uptime/navigation.ts
+++ b/x-pack/test/functional/services/uptime/navigation.ts
@@ -9,17 +9,27 @@ import { FtrProviderContext } from '../../ftr_provider_context';
 export function UptimeNavigationProvider({ getService, getPageObjects }: FtrProviderContext) {
   const retry = getService('retry');
   const testSubjects = getService('testSubjects');
-  const PageObjects = getPageObjects(['common', 'header']);
+  const PageObjects = getPageObjects(['common', 'timePicker', 'header']);
 
   const goToUptimeRoot = async () => {
-    await retry.tryForTime(30 * 1000, async () => {
-      await PageObjects.common.navigateToApp('uptime');
-      await PageObjects.header.waitUntilLoadingHasFinished();
-      await testSubjects.existOrFail('uptimeOverviewPage', { timeout: 2000 });
+    // Check if are already on overview uptime page, we don't need to repeat the step
+    await retry.tryForTime(60 * 1000, async () => {
+      if (await testSubjects.exists('uptimeSettingsToOverviewLink', { timeout: 0 })) {
+        await testSubjects.click('uptimeSettingsToOverviewLink');
+        await testSubjects.existOrFail('uptimeOverviewPage', { timeout: 2000 });
+      } else if (!(await testSubjects.exists('uptimeOverviewPage', { timeout: 0 }))) {
+        await PageObjects.common.navigateToApp('uptime');
+        await PageObjects.header.waitUntilLoadingHasFinished();
+        await testSubjects.existOrFail('uptimeOverviewPage', { timeout: 2000 });
+      }
     });
   };
 
   return {
+    async refreshApp() {
+      await testSubjects.click('superDatePickerApplyTimeButton');
+    },
+
     async goToUptime() {
       await goToUptimeRoot();
     },
@@ -30,17 +40,29 @@ export function UptimeNavigationProvider({ getService, getPageObjects }: FtrProv
       await testSubjects.existOrFail('uptimeSettingsPage', { timeout: 2000 });
     },
 
-    goToMonitor: async (monitorId: string, monitorName?: string) => {
-      await testSubjects.click(`monitor-page-link-${monitorId}`, 5000);
-      if (
-        monitorName &&
-        (await testSubjects.getVisibleText('monitor-page-title')) !== monitorName
-      ) {
-        throw new Error('Expected monitor name not found');
+    checkIfOnMonitorPage: async (monitorId: string) => {
+      const monitorPage = await testSubjects.exists('uptimeMonitorPage', { timeout: 1000 });
+      if (monitorId && monitorPage) {
+        const thisMonitorPage =
+          (await testSubjects.getVisibleText('monitor-page-title')) === monitorId;
+        return monitorPage && thisMonitorPage;
+      } else {
+        return monitorPage;
+      }
+    },
+
+    goToMonitor: async (monitorId: string) => {
+      if (!(await testSubjects.exists('uptimeMonitorPage', { timeout: 0 }))) {
+        await testSubjects.click(`monitor-page-link-${monitorId}`);
+        await testSubjects.existOrFail('uptimeMonitorPage', {
+          timeout: 30000,
+        });
       }
-      await testSubjects.existOrFail('uptimeMonitorPage', {
-        timeout: 30000,
-      });
+    },
+
+    async loadDataAndGoToMonitorPage(dateStart: string, dateEnd: string, monitorId: string) {
+      await PageObjects.timePicker.setAbsoluteRange(dateStart, dateEnd);
+      await this.goToMonitor(monitorId);
     },
   };
 }
diff --git a/x-pack/test/functional/services/uptime/uptime.ts b/x-pack/test/functional/services/uptime/uptime.ts
index c96bd0e0c4675..601feb6b0646e 100644
--- a/x-pack/test/functional/services/uptime/uptime.ts
+++ b/x-pack/test/functional/services/uptime/uptime.ts
@@ -11,6 +11,7 @@ import { UptimeCommonProvider } from './common';
 import { UptimeMonitorProvider } from './monitor';
 import { UptimeNavigationProvider } from './navigation';
 import { UptimeAlertsProvider } from './alerts';
+import { UptimeMLAnomalyProvider } from './ml_anomaly';
 
 export function UptimeProvider(context: FtrProviderContext) {
   const common = UptimeCommonProvider(context);
@@ -18,6 +19,7 @@ export function UptimeProvider(context: FtrProviderContext) {
   const monitor = UptimeMonitorProvider(context);
   const navigation = UptimeNavigationProvider(context);
   const alerts = UptimeAlertsProvider(context);
+  const ml = UptimeMLAnomalyProvider(context);
 
   return {
     common,
@@ -25,5 +27,6 @@ export function UptimeProvider(context: FtrProviderContext) {
     monitor,
     navigation,
     alerts,
+    ml,
   };
 }

From 36b4ad98883442c329f455d0d6ddd54ebf5e1b86 Mon Sep 17 00:00:00 2001
From: Dario Gieselaar <dario.gieselaar@elastic.co>
Date: Mon, 13 Apr 2020 14:06:20 +0200
Subject: [PATCH 73/78] [APM] Separate count/retainment telemetry requests
 (#63225)

Separate count/retainment telemetry requests to make them less prone to timing out.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../collect_data_telemetry/tasks.ts           | 40 ++++++++++++++-----
 1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts
index 85f233de2086d..e9801272cd57b 100644
--- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts
+++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts
@@ -61,10 +61,10 @@ export const tasks: TelemetryTask[] = [
         return prevJob.then(async data => {
           const { processorEvent, timeRange } = current;
 
-          const response = await search({
+          const totalHitsResponse = await search({
             index: indicesByProcessorEvent[processorEvent],
             body: {
-              size: 1,
+              size: 0,
               query: {
                 bool: {
                   filter: [
@@ -83,25 +83,43 @@ export const tasks: TelemetryTask[] = [
                   ]
                 }
               },
-              sort: {
-                '@timestamp': 'asc'
-              },
-              _source: ['@timestamp'],
               track_total_hits: true
             }
           });
 
-          const event = response.hits.hits[0]?._source as {
-            '@timestamp': number;
-          };
+          const retainmentResponse =
+            timeRange === 'all'
+              ? await search({
+                  index: indicesByProcessorEvent[processorEvent],
+                  body: {
+                    query: {
+                      bool: {
+                        filter: [
+                          { term: { [PROCESSOR_EVENT]: processorEvent } }
+                        ]
+                      }
+                    },
+                    sort: {
+                      '@timestamp': 'asc'
+                    },
+                    _source: ['@timestamp']
+                  }
+                })
+              : null;
+
+          const event = retainmentResponse?.hits.hits[0]?._source as
+            | {
+                '@timestamp': number;
+              }
+            | undefined;
 
           return merge({}, data, {
             counts: {
               [processorEvent]: {
-                [timeRange]: response.hits.total.value
+                [timeRange]: totalHitsResponse.hits.total.value
               }
             },
-            ...(timeRange === 'all' && event
+            ...(event
               ? {
                   retainment: {
                     [processorEvent]: {

From bbd501ea517225c551decd2f649255e7ff098c00 Mon Sep 17 00:00:00 2001
From: Thomas Neirynck <thomas@elastic.co>
Date: Mon, 13 Apr 2020 09:24:16 -0400
Subject: [PATCH 74/78] [Maps] Cleanup sources (#63175)

- Introduces additional TS typing for sources
- Organizes sources in sub-directories by type
- migrates XYZTMSSource to TS
---
 .../server/maps_telemetry/maps_telemetry.ts   |   2 +
 .../descriptor_types/descriptor_types.d.ts    |  26 ++-
 .../public/layers/blended_vector_layer.ts     |   6 +-
 x-pack/plugins/maps/public/layers/layer.d.ts  |   1 +
 .../public/layers/layer_wizard_registry.ts    |  20 +-
 .../{ => es_agg_source}/es_agg_source.d.ts    |  10 +-
 .../{ => es_agg_source}/es_agg_source.js      |   6 +-
 .../{ => es_agg_source}/es_agg_source.test.ts |  10 +-
 .../layers/sources/es_agg_source/index.ts     |   7 +
 .../sources/{ => es_source}/es_source.d.ts    |   8 +-
 .../sources/{ => es_source}/es_source.js      |  14 +-
 .../public/layers/sources/es_source/index.ts  |   7 +
 .../{ => es_term_source}/es_term_source.d.ts  |   4 +-
 .../{ => es_term_source}/es_term_source.js    |   8 +-
 .../es_term_source.test.js                    |   2 +-
 .../layers/sources/es_term_source/index.ts    |   7 +
 .../maps/public/layers/sources/source.d.ts    |  22 ++-
 .../public/layers/sources/source_registry.ts  |   3 +-
 .../public/layers/sources/tms_source/index.ts |   7 +
 .../sources/{ => tms_source}/tms_source.d.ts  |   3 +-
 .../sources/{ => tms_source}/tms_source.js    |   2 +-
 .../layers/sources/vector_source/index.ts     |   7 +
 .../{ => vector_source}/vector_source.d.ts    |   6 +-
 .../{ => vector_source}/vector_source.js      |  10 +-
 .../public/layers/sources/xyz_tms_source.d.ts |  11 --
 .../public/layers/sources/xyz_tms_source.js   | 187 ------------------
 .../layers/sources/xyz_tms_source/index.ts    |   8 +
 .../sources/xyz_tms_source/layer_wizard.tsx   |  27 +++
 .../sources/xyz_tms_source/xyz_tms_editor.tsx | 122 ++++++++++++
 .../xyz_tms_source.test.ts                    |  12 +-
 .../sources/xyz_tms_source/xyz_tms_source.ts  |  87 ++++++++
 .../plugins/maps/public/layers/tile_layer.js  |   4 +-
 .../maps/public/layers/tile_layer.test.ts     |   2 +-
 .../maps/public/layers/vector_layer.d.ts      |   4 +-
 34 files changed, 392 insertions(+), 270 deletions(-)
 rename x-pack/plugins/maps/public/layers/sources/{ => es_agg_source}/es_agg_source.d.ts (73%)
 rename x-pack/plugins/maps/public/layers/sources/{ => es_agg_source}/es_agg_source.js (95%)
 rename x-pack/plugins/maps/public/layers/sources/{ => es_agg_source}/es_agg_source.test.ts (89%)
 create mode 100644 x-pack/plugins/maps/public/layers/sources/es_agg_source/index.ts
 rename x-pack/plugins/maps/public/layers/sources/{ => es_source}/es_source.d.ts (78%)
 rename x-pack/plugins/maps/public/layers/sources/{ => es_source}/es_source.js (95%)
 create mode 100644 x-pack/plugins/maps/public/layers/sources/es_source/index.ts
 rename x-pack/plugins/maps/public/layers/sources/{ => es_term_source}/es_term_source.d.ts (77%)
 rename x-pack/plugins/maps/public/layers/sources/{ => es_term_source}/es_term_source.js (95%)
 rename x-pack/plugins/maps/public/layers/sources/{ => es_term_source}/es_term_source.test.js (98%)
 create mode 100644 x-pack/plugins/maps/public/layers/sources/es_term_source/index.ts
 create mode 100644 x-pack/plugins/maps/public/layers/sources/tms_source/index.ts
 rename x-pack/plugins/maps/public/layers/sources/{ => tms_source}/tms_source.d.ts (80%)
 rename x-pack/plugins/maps/public/layers/sources/{ => tms_source}/tms_source.js (94%)
 create mode 100644 x-pack/plugins/maps/public/layers/sources/vector_source/index.ts
 rename x-pack/plugins/maps/public/layers/sources/{ => vector_source}/vector_source.d.ts (91%)
 rename x-pack/plugins/maps/public/layers/sources/{ => vector_source}/vector_source.js (93%)
 delete mode 100644 x-pack/plugins/maps/public/layers/sources/xyz_tms_source.d.ts
 delete mode 100644 x-pack/plugins/maps/public/layers/sources/xyz_tms_source.js
 create mode 100644 x-pack/plugins/maps/public/layers/sources/xyz_tms_source/index.ts
 create mode 100644 x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx
 create mode 100644 x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_editor.tsx
 rename x-pack/plugins/maps/public/layers/sources/{ => xyz_tms_source}/xyz_tms_source.test.ts (71%)
 create mode 100644 x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts

diff --git a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts
index 5657e14622e9b..0300f22eeeb82 100644
--- a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts
+++ b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts
@@ -87,6 +87,8 @@ export function buildMapsTelemetry({
   const mapsCount = layerLists.length;
 
   const dataSourcesCount = layerLists.map(lList => {
+    // todo: not every source-descriptor has an id
+    // @ts-ignore
     const sourceIdList = lList.map((layer: LayerDescriptor) => layer.sourceDescriptor.id);
     return _.uniq(sourceIdList).length;
   });
diff --git a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts
index fb49e1aaebe1c..ff285877750c5 100644
--- a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts
+++ b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts
@@ -9,6 +9,11 @@ import { AGG_TYPE, GRID_RESOLUTION, RENDER_AS, SORT_ORDER, SCALING_TYPES } from
 import { VectorStyleDescriptor } from './style_property_descriptor_types';
 import { DataRequestDescriptor } from './data_request_descriptor_types';
 
+export type AttributionDescriptor = {
+  attributionText?: string;
+  attributionUrl?: string;
+};
+
 export type AbstractSourceDescriptor = {
   id?: string;
   type: string;
@@ -84,17 +89,26 @@ export type WMSSourceDescriptor = {
   attributionUrl: string;
 };
 
-export type XYZTMSSourceDescriptor = {
-  id: string;
-  type: string;
-  urlTemplate: string;
-};
+export type XYZTMSSourceDescriptor = AbstractSourceDescriptor &
+  AttributionDescriptor & {
+    urlTemplate: string;
+  };
 
 export type JoinDescriptor = {
   leftField: string;
   right: ESTermSourceDescriptor;
 };
 
+export type SourceDescriptor =
+  | XYZTMSSourceDescriptor
+  | WMSSourceDescriptor
+  | KibanaTilemapSourceDescriptor
+  | KibanaRegionmapSourceDescriptor
+  | ESTermSourceDescriptor
+  | ESSearchSourceDescriptor
+  | ESGeoGridSourceDescriptor
+  | EMSFileSourceDescriptor;
+
 export type LayerDescriptor = {
   __dataRequests?: DataRequestDescriptor[];
   __isInErrorState?: boolean;
@@ -104,7 +118,7 @@ export type LayerDescriptor = {
   label?: string;
   minZoom?: number;
   maxZoom?: number;
-  sourceDescriptor: AbstractSourceDescriptor;
+  sourceDescriptor: SourceDescriptor;
   type?: string;
   visible?: boolean;
 };
diff --git a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts
index f5526ad703dd2..80bf0299380d9 100644
--- a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts
+++ b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts
@@ -34,6 +34,7 @@ import {
   VectorStyleDescriptor,
   SizeDynamicOptions,
   DynamicStylePropertyOptions,
+  VectorLayerDescriptor,
 } from '../../common/descriptor_types';
 
 const ACTIVE_COUNT_DATA_ID = 'ACTIVE_COUNT_DATA_ID';
@@ -147,7 +148,10 @@ function getClusterStyleDescriptor(
 export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
   static type = LAYER_TYPE.BLENDED_VECTOR;
 
-  static createDescriptor(options: VectorLayerArguments, mapColors: string[]) {
+  static createDescriptor(
+    options: VectorLayerDescriptor,
+    mapColors: string[]
+  ): VectorLayerDescriptor {
     const layerDescriptor = VectorLayer.createDescriptor(options, mapColors);
     layerDescriptor.type = BlendedVectorLayer.type;
     return layerDescriptor;
diff --git a/x-pack/plugins/maps/public/layers/layer.d.ts b/x-pack/plugins/maps/public/layers/layer.d.ts
index de59642ede8ab..8fb69734d3d06 100644
--- a/x-pack/plugins/maps/public/layers/layer.d.ts
+++ b/x-pack/plugins/maps/public/layers/layer.d.ts
@@ -25,6 +25,7 @@ export interface ILayerArguments {
 }
 
 export class AbstractLayer implements ILayer {
+  static createDescriptor(options: Partial<LayerDescriptor>, mapColors?: string[]): LayerDescriptor;
   constructor(layerArguments: ILayerArguments);
   getBounds(mapFilters: MapFilters): Promise<MapExtent>;
   getDataRequest(id: string): DataRequest | undefined;
diff --git a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts
index 3ef4701269994..cb87aeaa9da3f 100644
--- a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts
+++ b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts
@@ -5,17 +5,21 @@
  */
 /* eslint-disable @typescript-eslint/consistent-type-definitions */
 
-type LayerWizard = {
+import { ReactElement } from 'react';
+import { ISource } from './sources/source';
+
+export type PreviewSourceHandler = (source: ISource | null) => void;
+
+export type RenderWizardArguments = {
+  onPreviewSource: PreviewSourceHandler;
+  inspectorAdapters: object;
+};
+
+export type LayerWizard = {
   description: string;
   icon: string;
   isIndexingSource?: boolean;
-  renderWizard({
-    onPreviewSource,
-    inspectorAdapters,
-  }: {
-    onPreviewSource: () => void;
-    inspectorAdapters: unknown;
-  }): unknown;
+  renderWizard(renderWizardArguments: RenderWizardArguments): ReactElement<any>;
   title: string;
 };
 
diff --git a/x-pack/plugins/maps/public/layers/sources/es_agg_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.d.ts
similarity index 73%
rename from x-pack/plugins/maps/public/layers/sources/es_agg_source.d.ts
rename to x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.d.ts
index 99ee1ec652b54..a93f9121d1e62 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_agg_source.d.ts
+++ b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.d.ts
@@ -4,11 +4,11 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { IESSource } from './es_source';
-import { AbstractESSource } from './es_source';
-import { AGG_TYPE } from '../../../common/constants';
-import { IESAggField } from '../fields/es_agg_field';
-import { AbstractESAggSourceDescriptor } from '../../../common/descriptor_types';
+import { IESSource } from '../es_source';
+import { AbstractESSource } from '../es_source';
+import { AGG_TYPE } from '../../../../common/constants';
+import { IESAggField } from '../../fields/es_agg_field';
+import { AbstractESAggSourceDescriptor } from '../../../../common/descriptor_types';
 
 export interface IESAggSource extends IESSource {
   getAggKey(aggType: AGG_TYPE, fieldName: string): string;
diff --git a/x-pack/plugins/maps/public/layers/sources/es_agg_source.js b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js
similarity index 95%
rename from x-pack/plugins/maps/public/layers/sources/es_agg_source.js
rename to x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js
index 9f4b89cadc777..c6197f137f212 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_agg_source.js
+++ b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js
@@ -5,15 +5,15 @@
  */
 
 import { i18n } from '@kbn/i18n';
-import { AbstractESSource } from './es_source';
-import { esAggFieldsFactory } from '../fields/es_agg_field';
+import { AbstractESSource } from '../es_source';
+import { esAggFieldsFactory } from '../../fields/es_agg_field';
 
 import {
   AGG_TYPE,
   COUNT_PROP_LABEL,
   COUNT_PROP_NAME,
   FIELD_ORIGIN,
-} from '../../../common/constants';
+} from '../../../../common/constants';
 
 export const AGG_DELIMITER = '_of_';
 
diff --git a/x-pack/plugins/maps/public/layers/sources/es_agg_source.test.ts b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.test.ts
similarity index 89%
rename from x-pack/plugins/maps/public/layers/sources/es_agg_source.test.ts
rename to x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.test.ts
index 848091586eb9c..87abbedfdf50e 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_agg_source.test.ts
+++ b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.test.ts
@@ -4,12 +4,12 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AbstractESAggSource } from './es_agg_source';
-import { IField } from '../fields/field';
-import { IESAggField } from '../fields/es_agg_field';
+import { AbstractESAggSource } from '../es_agg_source';
+import { IField } from '../../fields/field';
+import { IESAggField } from '../../fields/es_agg_field';
 import _ from 'lodash';
-import { AGG_TYPE } from '../../../common/constants';
-import { AggDescriptor } from '../../../common/descriptor_types';
+import { AGG_TYPE } from '../../../../common/constants';
+import { AggDescriptor } from '../../../../common/descriptor_types';
 
 jest.mock('ui/new_platform');
 
diff --git a/x-pack/plugins/maps/public/layers/sources/es_agg_source/index.ts b/x-pack/plugins/maps/public/layers/sources/es_agg_source/index.ts
new file mode 100644
index 0000000000000..cbf4eceefd432
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/es_agg_source/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './es_agg_source';
diff --git a/x-pack/plugins/maps/public/layers/sources/es_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts
similarity index 78%
rename from x-pack/plugins/maps/public/layers/sources/es_source.d.ts
rename to x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts
index 65851d0e7bd38..092dc3bf0d5a8 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_source.d.ts
+++ b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts
@@ -4,10 +4,10 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AbstractVectorSource } from './vector_source';
-import { IVectorSource } from './vector_source';
-import { IndexPattern, SearchSource } from '../../../../../../src/plugins/data/public';
-import { VectorSourceRequestMeta } from '../../../common/descriptor_types';
+import { AbstractVectorSource } from '../vector_source';
+import { IVectorSource } from '../vector_source';
+import { IndexPattern, SearchSource } from '../../../../../../../src/plugins/data/public';
+import { VectorSourceRequestMeta } from '../../../../common/descriptor_types';
 
 export interface IESSource extends IVectorSource {
   getId(): string;
diff --git a/x-pack/plugins/maps/public/layers/sources/es_source.js b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js
similarity index 95%
rename from x-pack/plugins/maps/public/layers/sources/es_source.js
rename to x-pack/plugins/maps/public/layers/sources/es_source/es_source.js
index d90a802a38344..3402e367cbd73 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_source.js
+++ b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js
@@ -4,23 +4,23 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AbstractVectorSource } from './vector_source';
+import { AbstractVectorSource } from '../vector_source';
 import {
   getAutocompleteService,
   fetchSearchSourceAndRecordWithInspector,
   getIndexPatternService,
   SearchSource,
   getTimeFilter,
-} from '../../kibana_services';
-import { createExtentFilter } from '../../elasticsearch_geo_utils';
+} from '../../../kibana_services';
+import { createExtentFilter } from '../../../elasticsearch_geo_utils';
 import _ from 'lodash';
 import { i18n } from '@kbn/i18n';
 import uuid from 'uuid/v4';
 // eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { copyPersistentState } from '../../reducers/util';
-import { ES_GEO_FIELD_TYPE } from '../../../common/constants';
-import { DataRequestAbortError } from '../util/data_request';
-import { expandToTileBoundaries } from './es_geo_grid_source/geo_tile_utils';
+import { copyPersistentState } from '../../../reducers/util';
+import { ES_GEO_FIELD_TYPE } from '../../../../common/constants';
+import { DataRequestAbortError } from '../../util/data_request';
+import { expandToTileBoundaries } from '../es_geo_grid_source/geo_tile_utils';
 
 export class AbstractESSource extends AbstractVectorSource {
   constructor(descriptor, inspectorAdapters) {
diff --git a/x-pack/plugins/maps/public/layers/sources/es_source/index.ts b/x-pack/plugins/maps/public/layers/sources/es_source/index.ts
new file mode 100644
index 0000000000000..227a4dd634457
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/es_source/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './es_source';
diff --git a/x-pack/plugins/maps/public/layers/sources/es_term_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts
similarity index 77%
rename from x-pack/plugins/maps/public/layers/sources/es_term_source.d.ts
rename to x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts
index 44cdc851b4fc7..701bd5e2c8b5e 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_term_source.d.ts
+++ b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts
@@ -4,8 +4,8 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { IField } from '../fields/field';
-import { IESAggSource } from './es_agg_source';
+import { IField } from '../../fields/field';
+import { IESAggSource } from '../es_agg_source';
 
 export interface IESTermSource extends IESAggSource {
   getTermField(): IField;
diff --git a/x-pack/plugins/maps/public/layers/sources/es_term_source.js b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js
similarity index 95%
rename from x-pack/plugins/maps/public/layers/sources/es_term_source.js
rename to x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js
index 3ce0fb58aba19..826197cc4fec7 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_term_source.js
+++ b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js
@@ -7,10 +7,10 @@
 import _ from 'lodash';
 
 import { i18n } from '@kbn/i18n';
-import { DEFAULT_MAX_BUCKETS_LIMIT, FIELD_ORIGIN, AGG_TYPE } from '../../../common/constants';
-import { ESDocField } from '../fields/es_doc_field';
-import { AbstractESAggSource, AGG_DELIMITER } from './es_agg_source';
-import { getField, addFieldToDSL, extractPropertiesFromBucket } from '../util/es_agg_utils';
+import { DEFAULT_MAX_BUCKETS_LIMIT, FIELD_ORIGIN, AGG_TYPE } from '../../../../common/constants';
+import { ESDocField } from '../../fields/es_doc_field';
+import { AbstractESAggSource, AGG_DELIMITER } from '../es_agg_source';
+import { getField, addFieldToDSL, extractPropertiesFromBucket } from '../../util/es_agg_utils';
 
 const TERMS_AGG_NAME = 'join';
 
diff --git a/x-pack/plugins/maps/public/layers/sources/es_term_source.test.js b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.test.js
similarity index 98%
rename from x-pack/plugins/maps/public/layers/sources/es_term_source.test.js
rename to x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.test.js
index 14ffd068df465..b6cd3b670d3ce 100644
--- a/x-pack/plugins/maps/public/layers/sources/es_term_source.test.js
+++ b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.test.js
@@ -7,7 +7,7 @@
 import { ESTermSource, extractPropertiesMap } from './es_term_source';
 
 jest.mock('ui/new_platform');
-jest.mock('../vector_layer', () => {});
+jest.mock('../../vector_layer', () => {});
 
 const indexPatternTitle = 'myIndex';
 const termFieldName = 'myTermField';
diff --git a/x-pack/plugins/maps/public/layers/sources/es_term_source/index.ts b/x-pack/plugins/maps/public/layers/sources/es_term_source/index.ts
new file mode 100644
index 0000000000000..6fad8384c690d
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/es_term_source/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './es_term_source';
diff --git a/x-pack/plugins/maps/public/layers/sources/source.d.ts b/x-pack/plugins/maps/public/layers/sources/source.d.ts
index e1706ad7b7d77..a1581b826d9a6 100644
--- a/x-pack/plugins/maps/public/layers/sources/source.d.ts
+++ b/x-pack/plugins/maps/public/layers/sources/source.d.ts
@@ -3,10 +3,21 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
+/* eslint-disable @typescript-eslint/consistent-type-definitions */
 
-import { AbstractSourceDescriptor } from '../../../common/descriptor_types';
+import { AbstractSourceDescriptor, LayerDescriptor } from '../../../common/descriptor_types';
 import { ILayer } from '../layer';
 
+export type ImmutableSourceProperty = {
+  label: string;
+  value: string;
+};
+
+export type Attribution = {
+  url: string;
+  label: string;
+};
+
 export interface ISource {
   createDefaultLayer(): ILayer;
   destroy(): void;
@@ -18,13 +29,16 @@ export interface ISource {
   isQueryAware(): boolean;
   isRefreshTimerAware(): Promise<boolean>;
   isTimeAware(): Promise<boolean>;
+  getImmutableProperties(): Promise<ImmutableSourceProperty[]>;
+  getAttributions(): Promise<Attribution[]>;
 }
 
 export class AbstractSource implements ISource {
-  constructor(sourceDescriptor: AbstractSourceDescriptor, inspectorAdapters: object);
+  readonly _descriptor: AbstractSourceDescriptor;
+  constructor(sourceDescriptor: AbstractSourceDescriptor, inspectorAdapters?: object);
 
   destroy(): void;
-  createDefaultLayer(): ILayer;
+  createDefaultLayer(options?: LayerDescriptor, mapColors?: string[]): ILayer;
   getDisplayName(): Promise<string>;
   getInspectorAdapters(): object;
   isFieldAware(): boolean;
@@ -33,4 +47,6 @@ export class AbstractSource implements ISource {
   isQueryAware(): boolean;
   isRefreshTimerAware(): Promise<boolean>;
   isTimeAware(): Promise<boolean>;
+  getImmutableProperties(): Promise<ImmutableSourceProperty[]>;
+  getAttributions(): Promise<Attribution[]>;
 }
diff --git a/x-pack/plugins/maps/public/layers/sources/source_registry.ts b/x-pack/plugins/maps/public/layers/sources/source_registry.ts
index 518cab68b601b..d16b16af74e9d 100644
--- a/x-pack/plugins/maps/public/layers/sources/source_registry.ts
+++ b/x-pack/plugins/maps/public/layers/sources/source_registry.ts
@@ -5,12 +5,11 @@
  */
 /* eslint-disable @typescript-eslint/consistent-type-definitions */
 
-import { AbstractSourceDescriptor } from '../../../common/descriptor_types';
 import { ISource } from './source';
 
 type SourceRegistryEntry = {
   ConstructorFunction: new (
-    sourceDescriptor: AbstractSourceDescriptor,
+    sourceDescriptor: any, // this is the source-descriptor that corresponds specifically to the particular ISource instance
     inspectorAdapters: unknown
   ) => ISource;
   type: string;
diff --git a/x-pack/plugins/maps/public/layers/sources/tms_source/index.ts b/x-pack/plugins/maps/public/layers/sources/tms_source/index.ts
new file mode 100644
index 0000000000000..f6bb1c6bc34ec
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/tms_source/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './tms_source';
diff --git a/x-pack/plugins/maps/public/layers/sources/tms_source.d.ts b/x-pack/plugins/maps/public/layers/sources/tms_source/tms_source.d.ts
similarity index 80%
rename from x-pack/plugins/maps/public/layers/sources/tms_source.d.ts
rename to x-pack/plugins/maps/public/layers/sources/tms_source/tms_source.d.ts
index 90b6f28e050fd..b31138f4cdb86 100644
--- a/x-pack/plugins/maps/public/layers/sources/tms_source.d.ts
+++ b/x-pack/plugins/maps/public/layers/sources/tms_source/tms_source.d.ts
@@ -4,7 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AbstractSource, ISource } from './source';
+import { AbstractSource, Attribution, ISource } from '../source';
 
 export interface ITMSSource extends ISource {
   getUrlTemplate(): Promise<string>;
@@ -12,4 +12,5 @@ export interface ITMSSource extends ISource {
 
 export class AbstractTMSSource extends AbstractSource implements ITMSSource {
   getUrlTemplate(): Promise<string>;
+  getAttributions(): Promise<Attribution[]>;
 }
diff --git a/x-pack/plugins/maps/public/layers/sources/tms_source.js b/x-pack/plugins/maps/public/layers/sources/tms_source/tms_source.js
similarity index 94%
rename from x-pack/plugins/maps/public/layers/sources/tms_source.js
rename to x-pack/plugins/maps/public/layers/sources/tms_source/tms_source.js
index f2ec9f2a29378..13b8da11633bc 100644
--- a/x-pack/plugins/maps/public/layers/sources/tms_source.js
+++ b/x-pack/plugins/maps/public/layers/sources/tms_source/tms_source.js
@@ -4,7 +4,7 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { AbstractSource } from './source';
+import { AbstractSource } from '../source';
 
 export class AbstractTMSSource extends AbstractSource {
   async getUrlTemplate() {
diff --git a/x-pack/plugins/maps/public/layers/sources/vector_source/index.ts b/x-pack/plugins/maps/public/layers/sources/vector_source/index.ts
new file mode 100644
index 0000000000000..62e801d027634
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/vector_source/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './vector_source';
diff --git a/x-pack/plugins/maps/public/layers/sources/vector_source.d.ts b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts
similarity index 91%
rename from x-pack/plugins/maps/public/layers/sources/vector_source.d.ts
rename to x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts
index d597e64277186..63429830d9f4f 100644
--- a/x-pack/plugins/maps/public/layers/sources/vector_source.d.ts
+++ b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts
@@ -6,14 +6,14 @@
 /* eslint-disable @typescript-eslint/consistent-type-definitions */
 
 import { FeatureCollection } from 'geojson';
-import { AbstractSource, ISource } from './source';
-import { IField } from '../fields/field';
+import { AbstractSource, ISource } from '../source';
+import { IField } from '../../fields/field';
 import {
   ESSearchSourceResponseMeta,
   MapExtent,
   VectorSourceRequestMeta,
   VectorSourceSyncMeta,
-} from '../../../common/descriptor_types';
+} from '../../../../common/descriptor_types';
 
 export type GeoJsonFetchMeta = ESSearchSourceResponseMeta;
 
diff --git a/x-pack/plugins/maps/public/layers/sources/vector_source.js b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js
similarity index 93%
rename from x-pack/plugins/maps/public/layers/sources/vector_source.js
rename to x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js
index 7f97b1b21d189..bb37175b48655 100644
--- a/x-pack/plugins/maps/public/layers/sources/vector_source.js
+++ b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js
@@ -4,14 +4,14 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { VectorLayer } from '../vector_layer';
-import { TooltipProperty } from '../tooltips/tooltip_property';
-import { VectorStyle } from '../styles/vector/vector_style';
-import { AbstractSource } from './source';
+import { VectorLayer } from '../../vector_layer';
+import { TooltipProperty } from '../../tooltips/tooltip_property';
+import { VectorStyle } from '../../styles/vector/vector_style';
+import { AbstractSource } from './../source';
 import * as topojson from 'topojson-client';
 import _ from 'lodash';
 import { i18n } from '@kbn/i18n';
-import { VECTOR_SHAPE_TYPES } from './vector_feature_types';
+import { VECTOR_SHAPE_TYPES } from './../vector_feature_types';
 
 export class AbstractVectorSource extends AbstractSource {
   static async getGeoJson({ format, featureCollectionPath, fetchUrl }) {
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.d.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.d.ts
deleted file mode 100644
index 579c9debeab3e..0000000000000
--- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { AbstractTMSSource } from './tms_source';
-import { XYZTMSSourceDescriptor } from '../../../common/descriptor_types';
-
-export class XYZTMSSource extends AbstractTMSSource {
-  constructor(sourceDescriptor: XYZTMSSourceDescriptor, inspectorAdapters: unknown);
-}
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.js b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.js
deleted file mode 100644
index d53fbffd21512..0000000000000
--- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React, { Fragment } from 'react';
-import { EuiFieldText, EuiFormRow } from '@elastic/eui';
-
-import { AbstractTMSSource } from './tms_source';
-import { TileLayer } from '../tile_layer';
-import { i18n } from '@kbn/i18n';
-import { getDataSourceLabel, getUrlLabel } from '../../../common/i18n_getters';
-import _ from 'lodash';
-import { EMS_XYZ } from '../../../common/constants';
-import { registerSource } from './source_registry';
-
-const sourceTitle = i18n.translate('xpack.maps.source.ems_xyzTitle', {
-  defaultMessage: 'Tile Map Service',
-});
-
-export class XYZTMSSource extends AbstractTMSSource {
-  static type = EMS_XYZ;
-
-  static createDescriptor({ urlTemplate, attributionText, attributionUrl }) {
-    return {
-      type: XYZTMSSource.type,
-      urlTemplate,
-      attributionText,
-      attributionUrl,
-    };
-  }
-
-  async getImmutableProperties() {
-    return [
-      { label: getDataSourceLabel(), value: sourceTitle },
-      { label: getUrlLabel(), value: this._descriptor.urlTemplate },
-    ];
-  }
-
-  _createDefaultLayerDescriptor(options) {
-    return TileLayer.createDescriptor({
-      sourceDescriptor: this._descriptor,
-      ...options,
-    });
-  }
-
-  createDefaultLayer(options) {
-    return new TileLayer({
-      layerDescriptor: this._createDefaultLayerDescriptor(options),
-      source: this,
-    });
-  }
-
-  async getDisplayName() {
-    return this._descriptor.urlTemplate;
-  }
-
-  getAttributions() {
-    const { attributionText, attributionUrl } = this._descriptor;
-    const attributionComplete = !!attributionText && !!attributionUrl;
-
-    return attributionComplete
-      ? [
-          {
-            url: attributionUrl,
-            label: attributionText,
-          },
-        ]
-      : [];
-  }
-
-  getUrlTemplate() {
-    return this._descriptor.urlTemplate;
-  }
-}
-
-class XYZTMSEditor extends React.Component {
-  state = {
-    tmsInput: '',
-    tmsCanPreview: false,
-    attributionText: '',
-    attributionUrl: '',
-  };
-
-  _sourceConfigChange = _.debounce(updatedSourceConfig => {
-    if (this.state.tmsCanPreview) {
-      this.props.onSourceConfigChange(updatedSourceConfig);
-    }
-  }, 2000);
-
-  _handleTMSInputChange(e) {
-    const url = e.target.value;
-
-    const canPreview =
-      url.indexOf('{x}') >= 0 && url.indexOf('{y}') >= 0 && url.indexOf('{z}') >= 0;
-    this.setState(
-      {
-        tmsInput: url,
-        tmsCanPreview: canPreview,
-      },
-      () => this._sourceConfigChange({ urlTemplate: url })
-    );
-  }
-
-  _handleTMSAttributionChange(attributionUpdate) {
-    this.setState(attributionUpdate, () => {
-      const { attributionText, attributionUrl, tmsInput } = this.state;
-
-      if (tmsInput && attributionText && attributionUrl) {
-        this._sourceConfigChange({
-          urlTemplate: tmsInput,
-          attributionText,
-          attributionUrl,
-        });
-      }
-    });
-  }
-
-  render() {
-    const { attributionText, attributionUrl } = this.state;
-
-    return (
-      <Fragment>
-        <EuiFormRow label="Url">
-          <EuiFieldText
-            placeholder={'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'}
-            onChange={e => this._handleTMSInputChange(e)}
-          />
-        </EuiFormRow>
-        <EuiFormRow
-          label="Attribution text"
-          isInvalid={attributionUrl !== '' && attributionText === ''}
-          error={[
-            i18n.translate('xpack.maps.xyztmssource.attributionText', {
-              defaultMessage: 'Attribution url must have accompanying text',
-            }),
-          ]}
-        >
-          <EuiFieldText
-            placeholder={'© OpenStreetMap contributors'}
-            onChange={({ target }) =>
-              this._handleTMSAttributionChange({ attributionText: target.value })
-            }
-          />
-        </EuiFormRow>
-        <EuiFormRow
-          label="Attribution link"
-          isInvalid={attributionText !== '' && attributionUrl === ''}
-          error={[
-            i18n.translate('xpack.maps.xyztmssource.attributionLink', {
-              defaultMessage: 'Attribution text must have an accompanying link',
-            }),
-          ]}
-        >
-          <EuiFieldText
-            placeholder={'https://www.openstreetmap.org/copyright'}
-            onChange={({ target }) =>
-              this._handleTMSAttributionChange({ attributionUrl: target.value })
-            }
-          />
-        </EuiFormRow>
-      </Fragment>
-    );
-  }
-}
-
-registerSource({
-  ConstructorFunction: XYZTMSSource,
-  type: EMS_XYZ,
-});
-
-export const tmsLayerWizardConfig = {
-  description: i18n.translate('xpack.maps.source.ems_xyzDescription', {
-    defaultMessage: 'Tile map service configured in interface',
-  }),
-  icon: 'grid',
-  renderWizard: ({ onPreviewSource, inspectorAdapters }) => {
-    const onSourceConfigChange = sourceConfig => {
-      const sourceDescriptor = XYZTMSSource.createDescriptor(sourceConfig);
-      const source = new XYZTMSSource(sourceDescriptor, inspectorAdapters);
-      onPreviewSource(source);
-    };
-    return <XYZTMSEditor onSourceConfigChange={onSourceConfigChange} />;
-  },
-  title: sourceTitle,
-};
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/index.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/index.ts
new file mode 100644
index 0000000000000..c1116ad47a375
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './xyz_tms_source';
+export * from './layer_wizard';
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx
new file mode 100644
index 0000000000000..8b1ed588c8dd1
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+import { XYZTMSEditor, XYZTMSSourceConfig } from './xyz_tms_editor';
+import { XYZTMSSource, sourceTitle } from './xyz_tms_source';
+import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry';
+
+export const tmsLayerWizardConfig: LayerWizard = {
+  description: i18n.translate('xpack.maps.source.ems_xyzDescription', {
+    defaultMessage: 'Tile map service configured in interface',
+  }),
+  icon: 'grid',
+  renderWizard: ({ onPreviewSource }: RenderWizardArguments) => {
+    const onSourceConfigChange = (sourceConfig: XYZTMSSourceConfig) => {
+      const sourceDescriptor = XYZTMSSource.createDescriptor(sourceConfig);
+      const source = new XYZTMSSource(sourceDescriptor);
+      onPreviewSource(source);
+    };
+    return <XYZTMSEditor onSourceConfigChange={onSourceConfigChange} />;
+  },
+  title: sourceTitle,
+};
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_editor.tsx b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_editor.tsx
new file mode 100644
index 0000000000000..0ee0fbb23bcff
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_editor.tsx
@@ -0,0 +1,122 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+/* eslint-disable @typescript-eslint/consistent-type-definitions */
+
+import React, { Fragment, Component, ChangeEvent } from 'react';
+import _ from 'lodash';
+import { EuiFormRow, EuiFieldText } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { AttributionDescriptor } from '../../../../common/descriptor_types';
+
+export type XYZTMSSourceConfig = AttributionDescriptor & {
+  urlTemplate: string;
+};
+
+export interface Props {
+  onSourceConfigChange: (sourceConfig: XYZTMSSourceConfig) => void;
+}
+
+interface State {
+  tmsInput: string;
+  tmsCanPreview: boolean;
+  attributionText: string;
+  attributionUrl: string;
+}
+
+export class XYZTMSEditor extends Component<Props, State> {
+  state = {
+    tmsInput: '',
+    tmsCanPreview: false,
+    attributionText: '',
+    attributionUrl: '',
+  };
+
+  _sourceConfigChange = _.debounce((updatedSourceConfig: XYZTMSSourceConfig) => {
+    if (this.state.tmsCanPreview) {
+      this.props.onSourceConfigChange(updatedSourceConfig);
+    }
+  }, 2000);
+
+  _handleTMSInputChange(e: ChangeEvent<HTMLInputElement>) {
+    const url = e.target.value;
+
+    const canPreview =
+      url.indexOf('{x}') >= 0 && url.indexOf('{y}') >= 0 && url.indexOf('{z}') >= 0;
+    this.setState(
+      {
+        tmsInput: url,
+        tmsCanPreview: canPreview,
+      },
+      () => this._sourceConfigChange({ urlTemplate: url })
+    );
+  }
+
+  _handleTMSAttributionChange(attributionUpdate: AttributionDescriptor) {
+    this.setState(
+      {
+        attributionUrl: attributionUpdate.attributionUrl || '',
+        attributionText: attributionUpdate.attributionText || '',
+      },
+      () => {
+        const { attributionText, attributionUrl, tmsInput } = this.state;
+
+        if (tmsInput && attributionText && attributionUrl) {
+          this._sourceConfigChange({
+            urlTemplate: tmsInput,
+            attributionText,
+            attributionUrl,
+          });
+        }
+      }
+    );
+  }
+
+  render() {
+    const { attributionText, attributionUrl } = this.state;
+    return (
+      <Fragment>
+        <EuiFormRow label="Url">
+          <EuiFieldText
+            placeholder={'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'}
+            onChange={e => this._handleTMSInputChange(e)}
+          />
+        </EuiFormRow>
+        <EuiFormRow
+          label="Attribution text"
+          isInvalid={attributionUrl !== '' && attributionText === ''}
+          error={[
+            i18n.translate('xpack.maps.xyztmssource.attributionText', {
+              defaultMessage: 'Attribution url must have accompanying text',
+            }),
+          ]}
+        >
+          <EuiFieldText
+            placeholder={'© OpenStreetMap contributors'}
+            onChange={({ target }: ChangeEvent<HTMLInputElement>) =>
+              this._handleTMSAttributionChange({ attributionText: target.value })
+            }
+          />
+        </EuiFormRow>
+        <EuiFormRow
+          label="Attribution link"
+          isInvalid={attributionText !== '' && attributionUrl === ''}
+          error={[
+            i18n.translate('xpack.maps.xyztmssource.attributionLink', {
+              defaultMessage: 'Attribution text must have an accompanying link',
+            }),
+          ]}
+        >
+          <EuiFieldText
+            placeholder={'https://www.openstreetmap.org/copyright'}
+            onChange={({ target }: ChangeEvent<HTMLInputElement>) =>
+              this._handleTMSAttributionChange({ attributionUrl: target.value })
+            }
+          />
+        </EuiFormRow>
+      </Fragment>
+    );
+  }
+}
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.test.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts
similarity index 71%
rename from x-pack/plugins/maps/public/layers/sources/xyz_tms_source.test.ts
rename to x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts
index e5ab5e57122ba..8a5cfb01e5821 100644
--- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source.test.ts
+++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts
@@ -5,10 +5,10 @@
  */
 
 import { XYZTMSSource } from './xyz_tms_source';
-import { ILayer } from '../layer';
-import { TileLayer } from '../tile_layer';
-import { EMS_XYZ } from '../../../common/constants';
-import { XYZTMSSourceDescriptor } from '../../../common/descriptor_types';
+import { ILayer } from '../../layer';
+import { TileLayer } from '../../tile_layer';
+import { EMS_XYZ } from '../../../../common/constants';
+import { XYZTMSSourceDescriptor } from '../../../../common/descriptor_types';
 
 const descriptor: XYZTMSSourceDescriptor = {
   type: EMS_XYZ,
@@ -17,13 +17,13 @@ const descriptor: XYZTMSSourceDescriptor = {
 };
 describe('xyz Tilemap Source', () => {
   it('should create a tile-layer', () => {
-    const source = new XYZTMSSource(descriptor, null);
+    const source = new XYZTMSSource(descriptor);
     const layer: ILayer = source.createDefaultLayer();
     expect(layer instanceof TileLayer).toEqual(true);
   });
 
   it('should echo url template for url template', async () => {
-    const source = new XYZTMSSource(descriptor, null);
+    const source = new XYZTMSSource(descriptor);
     const template = await source.getUrlTemplate();
     expect(template).toEqual(descriptor.urlTemplate);
   });
diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts
new file mode 100644
index 0000000000000..dd96c31573316
--- /dev/null
+++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts
@@ -0,0 +1,87 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+import { TileLayer } from '../../tile_layer';
+import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters';
+import { EMS_XYZ } from '../../../../common/constants';
+import { registerSource } from '../source_registry';
+import { AbstractTMSSource } from '../tms_source';
+import { LayerDescriptor, XYZTMSSourceDescriptor } from '../../../../common/descriptor_types';
+import { Attribution, ImmutableSourceProperty } from '../source';
+import { XYZTMSSourceConfig } from './xyz_tms_editor';
+
+export const sourceTitle = i18n.translate('xpack.maps.source.ems_xyzTitle', {
+  defaultMessage: 'Tile Map Service',
+});
+
+export class XYZTMSSource extends AbstractTMSSource {
+  static type = EMS_XYZ;
+
+  readonly _descriptor: XYZTMSSourceDescriptor;
+
+  static createDescriptor({
+    urlTemplate,
+    attributionText,
+    attributionUrl,
+  }: XYZTMSSourceConfig): XYZTMSSourceDescriptor {
+    return {
+      type: XYZTMSSource.type,
+      urlTemplate,
+      attributionText,
+      attributionUrl,
+    };
+  }
+
+  constructor(sourceDescriptor: XYZTMSSourceDescriptor) {
+    super(sourceDescriptor);
+    this._descriptor = sourceDescriptor;
+  }
+
+  async getImmutableProperties(): Promise<ImmutableSourceProperty[]> {
+    return [
+      { label: getDataSourceLabel(), value: sourceTitle },
+      { label: getUrlLabel(), value: this._descriptor.urlTemplate },
+    ];
+  }
+
+  createDefaultLayer(options?: LayerDescriptor): TileLayer {
+    const layerDescriptor: LayerDescriptor = TileLayer.createDescriptor({
+      sourceDescriptor: this._descriptor,
+      ...options,
+    });
+    return new TileLayer({
+      layerDescriptor,
+      source: this,
+    });
+  }
+
+  async getDisplayName(): Promise<string> {
+    return this._descriptor.urlTemplate;
+  }
+
+  async getAttributions(): Promise<Attribution[]> {
+    const { attributionText, attributionUrl } = this._descriptor;
+    const attributionComplete = !!attributionText && !!attributionUrl;
+    return attributionComplete
+      ? [
+          {
+            url: attributionUrl as string,
+            label: attributionText as string,
+          },
+        ]
+      : [];
+  }
+
+  async getUrlTemplate(): Promise<string> {
+    return this._descriptor.urlTemplate;
+  }
+}
+
+registerSource({
+  ConstructorFunction: XYZTMSSource,
+  type: EMS_XYZ,
+});
diff --git a/x-pack/plugins/maps/public/layers/tile_layer.js b/x-pack/plugins/maps/public/layers/tile_layer.js
index aa2619e96f834..2ac60e12d137a 100644
--- a/x-pack/plugins/maps/public/layers/tile_layer.js
+++ b/x-pack/plugins/maps/public/layers/tile_layer.js
@@ -11,8 +11,8 @@ import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../common/constants';
 export class TileLayer extends AbstractLayer {
   static type = LAYER_TYPE.TILE;
 
-  static createDescriptor(options) {
-    const tileLayerDescriptor = super.createDescriptor(options);
+  static createDescriptor(options, mapColors) {
+    const tileLayerDescriptor = super.createDescriptor(options, mapColors);
     tileLayerDescriptor.type = TileLayer.type;
     tileLayerDescriptor.alpha = _.get(options, 'alpha', 1);
     return tileLayerDescriptor;
diff --git a/x-pack/plugins/maps/public/layers/tile_layer.test.ts b/x-pack/plugins/maps/public/layers/tile_layer.test.ts
index 1cb99dcbc1a70..43465eac7f3ce 100644
--- a/x-pack/plugins/maps/public/layers/tile_layer.test.ts
+++ b/x-pack/plugins/maps/public/layers/tile_layer.test.ts
@@ -17,7 +17,7 @@ const sourceDescriptor: XYZTMSSourceDescriptor = {
 };
 
 class MockTileSource extends AbstractTMSSource implements ITMSSource {
-  private readonly _descriptor: XYZTMSSourceDescriptor;
+  readonly _descriptor: XYZTMSSourceDescriptor;
   constructor(descriptor: XYZTMSSourceDescriptor) {
     super(descriptor, {});
     this._descriptor = descriptor;
diff --git a/x-pack/plugins/maps/public/layers/vector_layer.d.ts b/x-pack/plugins/maps/public/layers/vector_layer.d.ts
index 70fd9927b7732..88b1a1ce8535e 100644
--- a/x-pack/plugins/maps/public/layers/vector_layer.d.ts
+++ b/x-pack/plugins/maps/public/layers/vector_layer.d.ts
@@ -32,8 +32,8 @@ export interface IVectorLayer extends ILayer {
 
 export class VectorLayer extends AbstractLayer implements IVectorLayer {
   static createDescriptor(
-    options: VectorLayerArguments,
-    mapColors: string[]
+    options: Partial<VectorLayerDescriptor>,
+    mapColors?: string[]
   ): VectorLayerDescriptor;
 
   protected readonly _source: IVectorSource;

From e74d360adb1acfa2b4316d75d9ca5da56c9437e4 Mon Sep 17 00:00:00 2001
From: MadameSheema <snootchie.boochies@gmail.com>
Date: Mon, 13 Apr 2020 15:38:32 +0200
Subject: [PATCH 75/78] fixes test flakiness (#63331)

---
 .../signal_detection_rules.spec.ts            | 31 ++++++++++++++++---
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts
index 2d2db9e70255b..ce6a49b675ef1 100644
--- a/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts
+++ b/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts
@@ -7,11 +7,16 @@ import {
   FIFTH_RULE,
   FIRST_RULE,
   RULE_NAME,
+  RULE_SWITCH,
   SECOND_RULE,
   SEVENTH_RULE,
 } from '../screens/signal_detection_rules';
 
-import { goToManageSignalDetectionRules } from '../tasks/detections';
+import {
+  goToManageSignalDetectionRules,
+  waitForSignalsPanelToBeLoaded,
+  waitForSignalsIndexToBeCreated,
+} from '../tasks/detections';
 import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
 import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';
 import {
@@ -32,8 +37,10 @@ describe('Signal detection rules', () => {
     esArchiverUnload('prebuilt_rules_loaded');
   });
 
-  it.skip('Sorts by activated rules', () => {
+  it('Sorts by activated rules', () => {
     loginAndWaitForPageWithoutDateRange(DETECTIONS);
+    waitForSignalsPanelToBeLoaded();
+    waitForSignalsIndexToBeCreated();
     goToManageSignalDetectionRules();
     waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded();
     cy.get(RULE_NAME)
@@ -52,10 +59,24 @@ describe('Signal detection rules', () => {
 
             cy.get(RULE_NAME)
               .eq(FIRST_RULE)
-              .should('have.text', fifthRuleName);
-            cy.get(RULE_NAME)
+              .invoke('text')
+              .then(firstRuleName => {
+                cy.get(RULE_NAME)
+                  .eq(SECOND_RULE)
+                  .invoke('text')
+                  .then(secondRuleName => {
+                    const expectedRulesNames = `${firstRuleName} ${secondRuleName}`;
+                    cy.wrap(expectedRulesNames).should('include', fifthRuleName);
+                    cy.wrap(expectedRulesNames).should('include', seventhRuleName);
+                  });
+              });
+
+            cy.get(RULE_SWITCH)
+              .eq(FIRST_RULE)
+              .should('have.attr', 'role', 'switch');
+            cy.get(RULE_SWITCH)
               .eq(SECOND_RULE)
-              .should('have.text', seventhRuleName);
+              .should('have.attr', 'role', 'switch');
           });
       });
   });

From c604eb9e63dcb7fe89b25bb4bc3b4a1b23e221d2 Mon Sep 17 00:00:00 2001
From: Nathan Reese <reese.nathan@gmail.com>
Date: Mon, 13 Apr 2020 08:00:15 -0600
Subject: [PATCH 76/78] [Maps] fix regression in loading left join fields
 (#63325)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../maps/public/connected_components/layer_panel/index.js       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js
index b3ad3d1df68ce..256f52112ba97 100644
--- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js
+++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js
@@ -12,7 +12,7 @@ import { fitToLayerExtent, updateSourceProp } from '../../actions/map_actions';
 function mapStateToProps(state = {}) {
   const selectedLayer = getSelectedLayer(state);
   return {
-    key: selectedLayer ? selectedLayer.getId() : '',
+    key: selectedLayer ? `${selectedLayer.getId()}${selectedLayer.isJoinable()}` : '',
     selectedLayer,
   };
 }

From 8cef9457c1f4d07bdf19fbc4679768f261699311 Mon Sep 17 00:00:00 2001
From: Nicolas Chaulet <nicolas.chaulet@elastic.co>
Date: Mon, 13 Apr 2020 10:39:40 -0400
Subject: [PATCH 77/78] [Ingest] Update Create datasource UI to fit in one page
 (#62858)

---
 .../enrollment_instructions/shell/index.tsx   |   2 +-
 .../ingest_manager/components/header.tsx      |  37 +-
 .../components/confirm_modal.tsx              |  72 ++++
 .../components/index.ts                       |   1 +
 .../components/layout.tsx                     | 175 +++++----
 .../components/navigation.tsx                 |  85 -----
 .../create_datasource_page/constants.ts       |   7 -
 .../create_datasource_page/index.tsx          | 348 +++++++++---------
 .../step_configure_datasource.tsx             | 188 +---------
 .../step_define_datasource.tsx                | 165 +++++++++
 .../create_datasource_page/step_review.tsx    | 202 ----------
 .../step_select_config.tsx                    |  78 +---
 .../step_select_package.tsx                   |  54 +--
 .../agent_enrollment_flyout/instructions.tsx  |   2 +-
 .../sections/fleet/agent_list_page/index.tsx  |   4 +-
 .../translations/translations/ja-JP.json      |  20 -
 .../translations/translations/zh-CN.json      |  20 -
 17 files changed, 550 insertions(+), 910 deletions(-)
 create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/confirm_modal.tsx
 delete mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx
 create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_define_datasource.tsx
 delete mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx

diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx
index e6990927b926e..cb65e31fb74b5 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx
@@ -43,7 +43,7 @@ export const ShellEnrollmentInstructions: React.FunctionComponent<Props> = ({
   //   apiKey.api_key
   // } sh -c "$(curl ${kibanaUrl}/api/ingest_manager/fleet/install/${currentPlatform})"`;
 
-  const quickInstallInstructions = `./agent enroll ${kibanaUrl} ${apiKey.api_key}`;
+  const quickInstallInstructions = `./elastic-agent enroll ${kibanaUrl} ${apiKey.api_key}`;
 
   return (
     <>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx
index e1f29fdbeb323..1aab6d901a992 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx
@@ -7,14 +7,15 @@ import React, { memo } from 'react';
 import styled from 'styled-components';
 import { EuiFlexGroup, EuiFlexItem, EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui';
 import { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab';
+import { EuiFlexItemProps } from '@elastic/eui/src/components/flex/flex_item';
 
 const Container = styled.div`
   border-bottom: ${props => props.theme.eui.euiBorderThin};
   background-color: ${props => props.theme.eui.euiPageBackgroundColor};
 `;
 
-const Wrapper = styled.div`
-  max-width: 1200px;
+const Wrapper = styled.div<{ maxWidth?: number }>`
+  max-width: ${props => props.maxWidth || 1200}px;
   margin-left: auto;
   margin-right: auto;
   padding-top: ${props => props.theme.eui.paddingSizes.xl};
@@ -30,22 +31,36 @@ const Tabs = styled(EuiTabs)`
 `;
 
 export interface HeaderProps {
+  restrictHeaderWidth?: number;
   leftColumn?: JSX.Element;
   rightColumn?: JSX.Element;
+  rightColumnGrow?: EuiFlexItemProps['grow'];
   tabs?: EuiTabProps[];
 }
 
-const HeaderColumns: React.FC<Omit<HeaderProps, 'tabs'>> = memo(({ leftColumn, rightColumn }) => (
-  <EuiFlexGroup alignItems="center">
-    {leftColumn ? <EuiFlexItem>{leftColumn}</EuiFlexItem> : null}
-    {rightColumn ? <EuiFlexItem>{rightColumn}</EuiFlexItem> : null}
-  </EuiFlexGroup>
-));
+const HeaderColumns: React.FC<Omit<HeaderProps, 'tabs'>> = memo(
+  ({ leftColumn, rightColumn, rightColumnGrow }) => (
+    <EuiFlexGroup alignItems="center">
+      {leftColumn ? <EuiFlexItem>{leftColumn}</EuiFlexItem> : null}
+      {rightColumn ? <EuiFlexItem grow={rightColumnGrow}>{rightColumn}</EuiFlexItem> : null}
+    </EuiFlexGroup>
+  )
+);
 
-export const Header: React.FC<HeaderProps> = ({ leftColumn, rightColumn, tabs }) => (
+export const Header: React.FC<HeaderProps> = ({
+  leftColumn,
+  rightColumn,
+  rightColumnGrow,
+  tabs,
+  restrictHeaderWidth,
+}) => (
   <Container>
-    <Wrapper>
-      <HeaderColumns leftColumn={leftColumn} rightColumn={rightColumn} />
+    <Wrapper maxWidth={restrictHeaderWidth}>
+      <HeaderColumns
+        leftColumn={leftColumn}
+        rightColumn={rightColumn}
+        rightColumnGrow={rightColumnGrow}
+      />
       <EuiFlexGroup>
         {tabs ? (
           <EuiFlexItem>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/confirm_modal.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/confirm_modal.tsx
new file mode 100644
index 0000000000000..aa7eab8f5be8d
--- /dev/null
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/confirm_modal.tsx
@@ -0,0 +1,72 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { EuiCallOut, EuiOverlayMask, EuiConfirmModal, EuiSpacer } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { i18n } from '@kbn/i18n';
+import { AgentConfig } from '../../../../types';
+
+export const ConfirmCreateDatasourceModal: React.FunctionComponent<{
+  onConfirm: () => void;
+  onCancel: () => void;
+  agentCount: number;
+  agentConfig: AgentConfig;
+}> = ({ onConfirm, onCancel, agentCount, agentConfig }) => {
+  return (
+    <EuiOverlayMask>
+      <EuiConfirmModal
+        title={
+          <FormattedMessage
+            id="xpack.ingestManager.createDatasource.confirmModalTitle"
+            defaultMessage="Save and deploy changes"
+          />
+        }
+        onCancel={onCancel}
+        onConfirm={onConfirm}
+        cancelButtonText={
+          <FormattedMessage
+            id="xpack.ingestManager.deleteApiKeys.confirmModal.cancelButtonLabel"
+            defaultMessage="Cancel"
+          />
+        }
+        confirmButtonText={
+          <FormattedMessage
+            id="xpack.ingestManager.createDatasource.confirmModalConfirmButtonLabel"
+            defaultMessage="Save and deploy changes"
+          />
+        }
+        buttonColor="primary"
+      >
+        <EuiCallOut
+          iconType="iInCircle"
+          title={i18n.translate('xpack.ingestManager.createDatasource.confirmModalCalloutTitle', {
+            defaultMessage:
+              'This action will update {agentCount, plural, one {# agent} other {# agents}}',
+            values: {
+              agentCount,
+            },
+          })}
+        >
+          <FormattedMessage
+            id="xpack.ingestManager.createDatasource.confirmModalCalloutDescription"
+            defaultMessage="Fleet has detected that the selected agent configuration, {configName}, is already in use by
+            some of your agents. As a result of this action, Fleet will deploy updates to all agents
+            that use this configuration."
+            values={{
+              configName: <b>{agentConfig.name}</b>,
+            }}
+          />
+        </EuiCallOut>
+        <EuiSpacer size="l" />
+        <FormattedMessage
+          id="xpack.ingestManager.createDatasource.confirmModalDescription"
+          defaultMessage="This action can not be undone. Are you sure you wish to continue?"
+        />
+      </EuiConfirmModal>
+    </EuiOverlayMask>
+  );
+};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts
index 3bfca75668911..aa564690a6092 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/index.ts
@@ -5,4 +5,5 @@
  */
 export { CreateDatasourcePageLayout } from './layout';
 export { DatasourceInputPanel } from './datasource_input_panel';
+export { ConfirmCreateDatasourceModal } from './confirm_modal';
 export { DatasourceInputVarField } from './datasource_input_var_field';
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx
index dd242f366e8c0..73a7ba8ec119d 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx
@@ -19,108 +19,107 @@ import { WithHeaderLayout } from '../../../../layouts';
 import { AgentConfig, PackageInfo } from '../../../../types';
 import { PackageIcon } from '../../../../components/package_icon';
 import { CreateDatasourceFrom, CreateDatasourceStep } from '../types';
-import { CreateDatasourceStepsNavigation } from './navigation';
 
 export const CreateDatasourcePageLayout: React.FunctionComponent<{
   from: CreateDatasourceFrom;
   basePath: string;
   cancelUrl: string;
   maxStep: CreateDatasourceStep | '';
-  currentStep: CreateDatasourceStep;
   agentConfig?: AgentConfig;
   packageInfo?: PackageInfo;
-  restrictWidth?: number;
-}> = ({
-  from,
-  basePath,
-  cancelUrl,
-  maxStep,
-  currentStep,
-  agentConfig,
-  packageInfo,
-  restrictWidth,
-  children,
-}) => {
-  return (
-    <WithHeaderLayout
-      restrictWidth={restrictWidth}
-      leftColumn={
-        <EuiFlexGroup direction="column" gutterSize="s" alignItems="flexStart">
-          <EuiFlexItem>
-            <EuiButtonEmpty size="s" iconType="cross" flush="left" href={cancelUrl}>
+}> = ({ from, basePath, cancelUrl, maxStep, agentConfig, packageInfo, children }) => {
+  const leftColumn = (
+    <EuiFlexGroup direction="column" gutterSize="s" alignItems="flexStart">
+      <EuiFlexItem>
+        <EuiButtonEmpty size="s" iconType="arrowLeft" flush="left" href={cancelUrl}>
+          <FormattedMessage
+            id="xpack.ingestManager.createDatasource.cancelLinkText"
+            defaultMessage="Cancel"
+          />
+        </EuiButtonEmpty>
+      </EuiFlexItem>
+      <EuiFlexItem>
+        <EuiText>
+          <h1>
+            <FormattedMessage
+              id="xpack.ingestManager.createDatasource.pageTitle"
+              defaultMessage="Add data source"
+            />
+          </h1>
+        </EuiText>
+      </EuiFlexItem>
+      <EuiFlexItem>
+        <EuiSpacer size="s" />
+        <EuiText color="subdued" size="s">
+          {from === 'config' ? (
+            <FormattedMessage
+              id="xpack.ingestManager.createDatasource.pageDescriptionfromConfig"
+              defaultMessage="Follow the instructions below to add an integration to this agent configuration."
+            />
+          ) : (
+            <FormattedMessage
+              id="xpack.ingestManager.createDatasource.pageDescriptionfromPackage"
+              defaultMessage="Follow the instructions below to add this integration to an agent configuration."
+            />
+          )}
+        </EuiText>
+      </EuiFlexItem>
+    </EuiFlexGroup>
+  );
+  const rightColumn = (
+    <EuiFlexGroup justifyContent="flexEnd" direction={'row'} gutterSize="xl">
+      <EuiFlexItem grow={false}>
+        <EuiSpacer size="s" />
+        {agentConfig && from === 'config' ? (
+          <EuiDescriptionList style={{ textAlign: 'right' }} textStyle="reverse">
+            <EuiDescriptionListTitle>
+              <FormattedMessage
+                id="xpack.ingestManager.createDatasource.agentConfigurationNameLabel"
+                defaultMessage="Configuration"
+              />
+            </EuiDescriptionListTitle>
+            <EuiDescriptionListDescription>
+              {agentConfig?.name || '-'}
+            </EuiDescriptionListDescription>
+          </EuiDescriptionList>
+        ) : null}
+        {packageInfo && from === 'package' ? (
+          <EuiDescriptionList style={{ textAlign: 'right' }} textStyle="reverse">
+            <EuiDescriptionListTitle>
               <FormattedMessage
-                id="xpack.ingestManager.createDatasource.cancelLinkText"
-                defaultMessage="Cancel"
+                id="xpack.ingestManager.createDatasource.packageNameLabel"
+                defaultMessage="Integration"
               />
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-          <EuiFlexItem>
-            <EuiText>
-              <h1>
-                <FormattedMessage
-                  id="xpack.ingestManager.createDatasource.pageTitle"
-                  defaultMessage="Create data source"
-                />
-              </h1>
-            </EuiText>
-          </EuiFlexItem>
-          <EuiFlexItem>
-            <EuiSpacer size="s" />
-            <EuiFlexGroup direction={from === 'config' ? 'row' : 'rowReverse'} gutterSize="xl">
-              {agentConfig || from === 'config' ? (
+            </EuiDescriptionListTitle>
+            <EuiDescriptionListDescription>
+              <EuiFlexGroup justifyContent="flexEnd" alignItems="center" gutterSize="s">
                 <EuiFlexItem grow={false}>
-                  <EuiDescriptionList textStyle="reverse">
-                    <EuiDescriptionListTitle>
-                      <FormattedMessage
-                        id="xpack.ingestManager.createDatasource.agentConfigurationNameLabel"
-                        defaultMessage="Configuration"
-                      />
-                    </EuiDescriptionListTitle>
-                    <EuiDescriptionListDescription>
-                      {agentConfig?.name || '-'}
-                    </EuiDescriptionListDescription>
-                  </EuiDescriptionList>
+                  <PackageIcon
+                    packageName={packageInfo?.name || ''}
+                    version={packageInfo?.version || ''}
+                    icons={packageInfo?.icons}
+                    size="m"
+                  />
                 </EuiFlexItem>
-              ) : null}
-              {packageInfo || from === 'package' ? (
                 <EuiFlexItem grow={false}>
-                  <EuiDescriptionList textStyle="reverse">
-                    <EuiDescriptionListTitle>
-                      <FormattedMessage
-                        id="xpack.ingestManager.createDatasource.packageNameLabel"
-                        defaultMessage="Integration"
-                      />
-                    </EuiDescriptionListTitle>
-                    <EuiDescriptionListDescription>
-                      <EuiFlexGroup alignItems="center" gutterSize="s">
-                        <EuiFlexItem grow={false}>
-                          <PackageIcon
-                            packageName={packageInfo?.name || ''}
-                            version={packageInfo?.version || ''}
-                            icons={packageInfo?.icons}
-                            size="m"
-                          />
-                        </EuiFlexItem>
-                        <EuiFlexItem grow={false}>
-                          {packageInfo?.title || packageInfo?.name || '-'}
-                        </EuiFlexItem>
-                      </EuiFlexGroup>
-                    </EuiDescriptionListDescription>
-                  </EuiDescriptionList>
+                  {packageInfo?.title || packageInfo?.name || '-'}
                 </EuiFlexItem>
-              ) : null}
-            </EuiFlexGroup>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      }
-      rightColumn={
-        <CreateDatasourceStepsNavigation
-          from={from}
-          basePath={basePath}
-          maxStep={maxStep}
-          currentStep={currentStep}
-        />
-      }
+              </EuiFlexGroup>
+            </EuiDescriptionListDescription>
+          </EuiDescriptionList>
+        ) : null}
+      </EuiFlexItem>
+    </EuiFlexGroup>
+  );
+
+  const maxWidth = 770;
+  return (
+    <WithHeaderLayout
+      restrictHeaderWidth={maxWidth}
+      restrictWidth={maxWidth}
+      leftColumn={leftColumn}
+      rightColumn={rightColumn}
+      rightColumnGrow={false}
     >
       {children}
     </WithHeaderLayout>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx
deleted file mode 100644
index 7dae981e65c30..0000000000000
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/navigation.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import React from 'react';
-import styled from 'styled-components';
-import { useHistory } from 'react-router-dom';
-import { i18n } from '@kbn/i18n';
-import { EuiStepsHorizontal } from '@elastic/eui';
-import { CreateDatasourceFrom, CreateDatasourceStep } from '../types';
-import { WeightedCreateDatasourceSteps, CREATE_DATASOURCE_STEP_PATHS } from '../constants';
-
-const StepsHorizontal = styled(EuiStepsHorizontal)`
-  background: none;
-`;
-
-export const CreateDatasourceStepsNavigation: React.FunctionComponent<{
-  from: CreateDatasourceFrom;
-  basePath: string;
-  maxStep: CreateDatasourceStep | '';
-  currentStep: CreateDatasourceStep;
-}> = ({ from, basePath, maxStep, currentStep }) => {
-  const history = useHistory();
-
-  const steps = [
-    from === 'config'
-      ? {
-          title: i18n.translate('xpack.ingestManager.createDatasource.stepSelectPackageLabel', {
-            defaultMessage: 'Select integration',
-          }),
-          isSelected: currentStep === 'selectPackage',
-          isComplete:
-            WeightedCreateDatasourceSteps.indexOf('selectPackage') <=
-            WeightedCreateDatasourceSteps.indexOf(maxStep),
-          onClick: () => {
-            history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.selectPackage}`);
-          },
-        }
-      : {
-          title: i18n.translate('xpack.ingestManager.createDatasource.stepSelectConfigLabel', {
-            defaultMessage: 'Select configuration',
-          }),
-          isSelected: currentStep === 'selectConfig',
-          isComplete:
-            WeightedCreateDatasourceSteps.indexOf('selectConfig') <=
-            WeightedCreateDatasourceSteps.indexOf(maxStep),
-          onClick: () => {
-            history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.selectConfig}`);
-          },
-        },
-    {
-      title: i18n.translate('xpack.ingestManager.createDatasource.stepConfigureDatasourceLabel', {
-        defaultMessage: 'Configure data source',
-      }),
-      isSelected: currentStep === 'configure',
-      isComplete:
-        WeightedCreateDatasourceSteps.indexOf('configure') <=
-        WeightedCreateDatasourceSteps.indexOf(maxStep),
-      disabled:
-        WeightedCreateDatasourceSteps.indexOf(maxStep) <
-        WeightedCreateDatasourceSteps.indexOf('configure') - 1,
-      onClick: () => {
-        history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.configure}`);
-      },
-    },
-    {
-      title: i18n.translate('xpack.ingestManager.createDatasource.stepReviewLabel', {
-        defaultMessage: 'Review',
-      }),
-      isSelected: currentStep === 'review',
-      isComplete:
-        WeightedCreateDatasourceSteps.indexOf('review') <=
-        WeightedCreateDatasourceSteps.indexOf(maxStep),
-      disabled:
-        WeightedCreateDatasourceSteps.indexOf(maxStep) <
-        WeightedCreateDatasourceSteps.indexOf('review') - 1,
-      onClick: () => {
-        history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.review}`);
-      },
-    },
-  ];
-
-  return <StepsHorizontal steps={steps} />;
-};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/constants.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/constants.ts
index eea18179560a1..49223a8eb4531 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/constants.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/constants.ts
@@ -9,10 +9,3 @@ export const WeightedCreateDatasourceSteps = [
   'configure',
   'review',
 ];
-
-export const CREATE_DATASOURCE_STEP_PATHS = {
-  selectConfig: '/select-config',
-  selectPackage: '/select-package',
-  configure: '/configure',
-  review: '/review',
-};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
index 461bb750ca6f5..1ad579d591b21 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx
@@ -3,45 +3,74 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React, { useState } from 'react';
-import {
-  useRouteMatch,
-  HashRouter as Router,
-  Switch,
-  Route,
-  Redirect,
-  useHistory,
-} from 'react-router-dom';
+import React, { useState, useEffect } from 'react';
+import { useRouteMatch, useHistory } from 'react-router-dom';
+import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-import { EuiButtonEmpty } from '@elastic/eui';
+import {
+  EuiButtonEmpty,
+  EuiButton,
+  EuiSteps,
+  EuiBottomBar,
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiSpacer,
+} from '@elastic/eui';
+import { EuiStepProps } from '@elastic/eui/src/components/steps/step';
 import { AGENT_CONFIG_DETAILS_PATH } from '../../../constants';
 import { AgentConfig, PackageInfo, NewDatasource } from '../../../types';
-import { useLink, sendCreateDatasource } from '../../../hooks';
+import {
+  useLink,
+  sendCreateDatasource,
+  useCore,
+  useConfig,
+  sendGetAgentStatus,
+} from '../../../hooks';
 import { useLinks as useEPMLinks } from '../../epm/hooks';
-import { CreateDatasourcePageLayout } from './components';
+import { CreateDatasourcePageLayout, ConfirmCreateDatasourceModal } from './components';
 import { CreateDatasourceFrom, CreateDatasourceStep } from './types';
-import { CREATE_DATASOURCE_STEP_PATHS } from './constants';
-import { DatasourceValidationResults, validateDatasource } from './services';
+import { DatasourceValidationResults, validateDatasource, validationHasErrors } from './services';
 import { StepSelectPackage } from './step_select_package';
 import { StepSelectConfig } from './step_select_config';
 import { StepConfigureDatasource } from './step_configure_datasource';
-import { StepReviewDatasource } from './step_review';
+
+import { StepDefineDatasource } from './step_define_datasource';
 
 export const CreateDatasourcePage: React.FunctionComponent = () => {
+  const { notifications } = useCore();
+  const {
+    fleet: { enabled: isFleetEnabled },
+  } = useConfig();
   const {
     params: { configId, pkgkey },
-    path: matchPath,
     url: basePath,
   } = useRouteMatch();
   const history = useHistory();
   const from: CreateDatasourceFrom = configId ? 'config' : 'package';
   const [maxStep, setMaxStep] = useState<CreateDatasourceStep | ''>('');
-  const [isSaving, setIsSaving] = useState<boolean>(false);
 
   // Agent config and package info states
   const [agentConfig, setAgentConfig] = useState<AgentConfig>();
   const [packageInfo, setPackageInfo] = useState<PackageInfo>();
 
+  const agentConfigId = agentConfig?.id;
+  // Retrieve agent count
+  useEffect(() => {
+    const getAgentCount = async () => {
+      if (agentConfigId) {
+        const { data } = await sendGetAgentStatus({ configId: agentConfigId });
+        if (data?.results.total) {
+          setAgentCount(data.results.total);
+        }
+      }
+    };
+
+    if (isFleetEnabled && agentConfigId) {
+      getAgentCount();
+    }
+  }, [agentConfigId, isFleetEnabled]);
+  const [agentCount, setAgentCount] = useState<number>(0);
+
   // New datasource state
   const [datasource, setDatasource] = useState<NewDatasource>({
     name: '',
@@ -60,6 +89,7 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
     if (updatedPackageInfo) {
       setPackageInfo(updatedPackageInfo);
     } else {
+      setFormState('INVALID');
       setPackageInfo(undefined);
       setMaxStep('');
     }
@@ -73,6 +103,7 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
     if (updatedAgentConfig) {
       setAgentConfig(updatedAgentConfig);
     } else {
+      setFormState('INVALID');
       setAgentConfig(undefined);
       setMaxStep('');
     }
@@ -81,6 +112,8 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
     console.debug('Agent config updated', updatedAgentConfig);
   };
 
+  const hasErrors = validationResults ? validationHasErrors(validationResults) : false;
+
   // Update datasource method
   const updateDatasource = (updatedFields: Partial<NewDatasource>) => {
     const newDatasource = {
@@ -88,9 +121,18 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
       ...updatedFields,
     };
     setDatasource(newDatasource);
+
     // eslint-disable-next-line no-console
     console.debug('Datasource updated', newDatasource);
-    updateDatasourceValidation(newDatasource);
+    const newValidationResults = updateDatasourceValidation(newDatasource);
+    const hasPackage = newDatasource.package;
+    const hasValidationErrors = newValidationResults
+      ? validationHasErrors(newValidationResults)
+      : false;
+    const hasAgentConfig = newDatasource.config_id && newDatasource.config_id !== '';
+    if (hasPackage && hasAgentConfig && !hasValidationErrors) {
+      setFormState('VALID');
+    }
   };
 
   const updateDatasourceValidation = (newDatasource?: NewDatasource) => {
@@ -99,6 +141,8 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
       setValidationResults(newValidationResult);
       // eslint-disable-next-line no-console
       console.debug('Datasource validation results', newValidationResult);
+
+      return newValidationResult;
     }
   };
 
@@ -112,34 +156,37 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
   });
   const cancelUrl = from === 'config' ? CONFIG_URL : PACKAGE_URL;
 
-  // Redirect to first step
-  const redirectToFirstStep =
-    from === 'config' ? (
-      <Redirect to={`${basePath}${CREATE_DATASOURCE_STEP_PATHS.selectPackage}`} />
-    ) : (
-      <Redirect to={`${basePath}${CREATE_DATASOURCE_STEP_PATHS.selectConfig}`} />
-    );
-
-  // Url to first and second steps
-  const SELECT_PACKAGE_URL = useLink(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.selectPackage}`);
-  const SELECT_CONFIG_URL = useLink(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.selectConfig}`);
-  const CONFIGURE_DATASOURCE_URL = useLink(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.configure}`);
-  const firstStepUrl = from === 'config' ? SELECT_PACKAGE_URL : SELECT_CONFIG_URL;
-  const secondStepUrl = CONFIGURE_DATASOURCE_URL;
-
-  // Redirect to second step
-  const redirectToSecondStep = (
-    <Redirect to={`${basePath}${CREATE_DATASOURCE_STEP_PATHS.configure}`} />
-  );
-
   // Save datasource
+  const [formState, setFormState] = useState<
+    'VALID' | 'INVALID' | 'CONFIRM' | 'LOADING' | 'SUBMITTED'
+  >('INVALID');
   const saveDatasource = async () => {
-    setIsSaving(true);
+    setFormState('LOADING');
     const result = await sendCreateDatasource(datasource);
-    setIsSaving(false);
+    setFormState('SUBMITTED');
     return result;
   };
 
+  const onSubmit = async () => {
+    if (formState === 'VALID' && hasErrors) {
+      setFormState('INVALID');
+      return;
+    }
+    if (agentCount !== 0 && formState !== 'CONFIRM') {
+      setFormState('CONFIRM');
+      return;
+    }
+    const { error } = await saveDatasource();
+    if (!error) {
+      history.push(`${AGENT_CONFIG_DETAILS_PATH}${agentConfig ? agentConfig.id : configId}`);
+    } else {
+      notifications.toasts.addError(error, {
+        title: 'Error',
+      });
+      setFormState('VALID');
+    }
+  };
+
   const layoutProps = {
     from,
     basePath,
@@ -147,135 +194,108 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
     maxStep,
     agentConfig,
     packageInfo,
-    restrictWidth: 770,
   };
 
-  return (
-    <Router>
-      <Switch>
-        {/* Redirect to first step from `/` */}
-        {from === 'config' ? (
-          <Redirect
-            exact
-            from={`${matchPath}`}
-            to={`${matchPath}${CREATE_DATASOURCE_STEP_PATHS.selectPackage}`}
+  const steps: EuiStepProps[] = [
+    from === 'package'
+      ? {
+          title: i18n.translate('xpack.ingestManager.createDatasource.stepSelectAgentConfigTitle', {
+            defaultMessage: 'Select an agent configuration',
+          }),
+          children: (
+            <StepSelectConfig
+              pkgkey={pkgkey}
+              updatePackageInfo={updatePackageInfo}
+              agentConfig={agentConfig}
+              updateAgentConfig={updateAgentConfig}
+            />
+          ),
+        }
+      : {
+          title: i18n.translate('xpack.ingestManager.createDatasource.stepSelectPackageTitle', {
+            defaultMessage: 'Select an integration',
+          }),
+          children: (
+            <StepSelectPackage
+              agentConfigId={configId}
+              updateAgentConfig={updateAgentConfig}
+              packageInfo={packageInfo}
+              updatePackageInfo={updatePackageInfo}
+            />
+          ),
+        },
+    {
+      title: i18n.translate('xpack.ingestManager.createDatasource.stepDefineDatasourceTitle', {
+        defaultMessage: 'Define your data source',
+      }),
+      status: !packageInfo || !agentConfig ? 'disabled' : undefined,
+      children:
+        agentConfig && packageInfo ? (
+          <StepDefineDatasource
+            agentConfig={agentConfig}
+            packageInfo={packageInfo}
+            datasource={datasource}
+            updateDatasource={updateDatasource}
           />
-        ) : (
-          <Redirect
-            exact
-            from={`${matchPath}`}
-            to={`${matchPath}${CREATE_DATASOURCE_STEP_PATHS.selectConfig}`}
+        ) : null,
+    },
+    {
+      title: i18n.translate('xpack.ingestManager.createDatasource.stepConfgiureDatasourceTitle', {
+        defaultMessage: 'Select the data you want to collect',
+      }),
+      status: !packageInfo || !agentConfig ? 'disabled' : undefined,
+      children:
+        agentConfig && packageInfo ? (
+          <StepConfigureDatasource
+            agentConfig={agentConfig}
+            packageInfo={packageInfo}
+            datasource={datasource}
+            updateDatasource={updateDatasource}
+            validationResults={validationResults!}
+            submitAttempted={formState === 'INVALID'}
           />
-        )}
-
-        {/* First step, either render select package or select config depending on entry */}
-        {from === 'config' ? (
-          <Route path={`${matchPath}${CREATE_DATASOURCE_STEP_PATHS.selectPackage}`}>
-            <CreateDatasourcePageLayout {...layoutProps} currentStep="selectPackage">
-              <StepSelectPackage
-                agentConfigId={configId}
-                updateAgentConfig={updateAgentConfig}
-                packageInfo={packageInfo}
-                updatePackageInfo={updatePackageInfo}
-                cancelUrl={cancelUrl}
-                onNext={() => {
-                  setMaxStep('selectPackage');
-                  history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.configure}`);
-                }}
-              />
-            </CreateDatasourcePageLayout>
-          </Route>
-        ) : (
-          <Route path={`${matchPath}${CREATE_DATASOURCE_STEP_PATHS.selectConfig}`}>
-            <CreateDatasourcePageLayout {...layoutProps} currentStep="selectConfig">
-              <StepSelectConfig
-                pkgkey={pkgkey}
-                updatePackageInfo={updatePackageInfo}
-                agentConfig={agentConfig}
-                updateAgentConfig={updateAgentConfig}
-                cancelUrl={cancelUrl}
-                onNext={() => {
-                  setMaxStep('selectConfig');
-                  history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.configure}`);
-                }}
-              />
-            </CreateDatasourcePageLayout>
-          </Route>
-        )}
-
-        {/* Second step to configure data source, redirect to first step if agent config */}
-        {/* or package info isn't defined (i.e. after full page reload) */}
-        <Route path={`${matchPath}${CREATE_DATASOURCE_STEP_PATHS.configure}`}>
-          <CreateDatasourcePageLayout {...layoutProps} currentStep="configure">
-            {!agentConfig || !packageInfo ? (
-              redirectToFirstStep
-            ) : (
-              <StepConfigureDatasource
-                agentConfig={agentConfig}
-                packageInfo={packageInfo}
-                datasource={datasource}
-                updateDatasource={updateDatasource}
-                validationResults={validationResults!}
-                backLink={
-                  <EuiButtonEmpty href={firstStepUrl} iconType="arrowLeft" iconSide="left">
-                    {from === 'config' ? (
-                      <FormattedMessage
-                        id="xpack.ingestManager.createDatasource.changePackageLinkText"
-                        defaultMessage="Change integration"
-                      />
-                    ) : (
-                      <FormattedMessage
-                        id="xpack.ingestManager.createDatasource.changeConfigLinkText"
-                        defaultMessage="Change configuration"
-                      />
-                    )}
-                  </EuiButtonEmpty>
-                }
-                cancelUrl={cancelUrl}
-                onNext={() => {
-                  setMaxStep('configure');
-                  history.push(`${basePath}${CREATE_DATASOURCE_STEP_PATHS.review}`);
-                }}
+        ) : null,
+    },
+  ];
+  return (
+    <CreateDatasourcePageLayout {...layoutProps}>
+      {formState === 'CONFIRM' && agentConfig && (
+        <ConfirmCreateDatasourceModal
+          agentCount={agentCount}
+          agentConfig={agentConfig}
+          onConfirm={onSubmit}
+          onCancel={() => setFormState('VALID')}
+        />
+      )}
+      <EuiSteps steps={steps} />
+      <EuiSpacer size="l" />
+      <EuiBottomBar css={{ zIndex: 5 }} paddingSize="s">
+        <EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
+          <EuiFlexItem grow={false}>
+            <EuiButtonEmpty color="ghost" href={cancelUrl}>
+              <FormattedMessage
+                id="xpack.ingestManager.createDatasource.cancelButton"
+                defaultMessage="Cancel"
               />
-            )}
-          </CreateDatasourcePageLayout>
-        </Route>
-
-        {/* Third step to review, redirect to second step if data source name is missing */}
-        {/* (i.e. after full page reload) */}
-        <Route path={`${matchPath}${CREATE_DATASOURCE_STEP_PATHS.review}`}>
-          <CreateDatasourcePageLayout {...layoutProps} currentStep="review">
-            {!agentConfig || !datasource.name ? (
-              redirectToSecondStep
-            ) : (
-              <StepReviewDatasource
-                agentConfig={agentConfig}
-                datasource={datasource}
-                cancelUrl={cancelUrl}
-                isSubmitLoading={isSaving}
-                backLink={
-                  <EuiButtonEmpty href={secondStepUrl} iconType="arrowLeft" iconSide="left">
-                    <FormattedMessage
-                      id="xpack.ingestManager.createDatasource.editDatasourceLinkText"
-                      defaultMessage="Edit data source"
-                    />
-                  </EuiButtonEmpty>
-                }
-                onSubmit={async () => {
-                  const { error } = await saveDatasource();
-                  if (!error) {
-                    history.push(
-                      `${AGENT_CONFIG_DETAILS_PATH}${agentConfig ? agentConfig.id : configId}`
-                    );
-                  } else {
-                    // TODO: Handle save datasource error
-                  }
-                }}
+            </EuiButtonEmpty>
+          </EuiFlexItem>
+          <EuiFlexItem grow={false}>
+            <EuiButton
+              onClick={onSubmit}
+              isLoading={formState === 'LOADING'}
+              disabled={formState !== 'VALID'}
+              iconType="save"
+              color="primary"
+              fill
+            >
+              <FormattedMessage
+                id="xpack.ingestManager.createDatasource.saveButton"
+                defaultMessage="Save data source"
               />
-            )}
-          </CreateDatasourcePageLayout>
-        </Route>
-      </Switch>
-    </Router>
+            </EuiButton>
+          </EuiFlexItem>
+        </EuiFlexGroup>
+      </EuiBottomBar>
+    </CreateDatasourcePageLayout>
   );
 };
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx
index 105d6c66a5704..843891b63ca01 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_configure_datasource.tsx
@@ -3,23 +3,18 @@
  * or more contributor license agreements. Licensed under the Elastic License;
  * you may not use this file except in compliance with the Elastic License.
  */
-import React, { useEffect, useState, Fragment } from 'react';
-import { i18n } from '@kbn/i18n';
+import React, { useEffect } from 'react';
 import { FormattedMessage } from '@kbn/i18n/react';
 import {
-  EuiSteps,
   EuiPanel,
   EuiFlexGroup,
   EuiFlexItem,
-  EuiFormRow,
-  EuiButtonEmpty,
   EuiSpacer,
   EuiEmptyPrompt,
   EuiText,
-  EuiButton,
-  EuiComboBox,
   EuiCallOut,
 } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
 import {
   AgentConfig,
   PackageInfo,
@@ -30,7 +25,7 @@ import {
 import { Loading } from '../../../components';
 import { packageToConfigDatasourceInputs } from '../../../services';
 import { DatasourceValidationResults, validationHasErrors } from './services';
-import { DatasourceInputPanel, DatasourceInputVarField } from './components';
+import { DatasourceInputPanel } from './components';
 
 export const StepConfigureDatasource: React.FunctionComponent<{
   agentConfig: AgentConfig;
@@ -38,24 +33,17 @@ export const StepConfigureDatasource: React.FunctionComponent<{
   datasource: NewDatasource;
   updateDatasource: (fields: Partial<NewDatasource>) => void;
   validationResults: DatasourceValidationResults;
-  backLink: JSX.Element;
-  cancelUrl: string;
-  onNext: () => void;
+  submitAttempted: boolean;
 }> = ({
   agentConfig,
   packageInfo,
   datasource,
   updateDatasource,
   validationResults,
-  backLink,
-  cancelUrl,
-  onNext,
+  submitAttempted,
 }) => {
   // Form show/hide states
-  const [isShowingAdvancedDefine, setIsShowingAdvancedDefine] = useState<boolean>(false);
 
-  // Form submit state
-  const [submitAttempted, setSubmitAttempted] = useState<boolean>(false);
   const hasErrors = validationResults ? validationHasErrors(validationResults) : false;
 
   // Update datasource's package and config info
@@ -95,107 +83,6 @@ export const StepConfigureDatasource: React.FunctionComponent<{
     }
   }, [datasource.package, datasource.config_id, agentConfig, packageInfo, updateDatasource]);
 
-  // Step A, define datasource
-  const renderDefineDatasource = () => (
-    <EuiPanel>
-      <EuiFlexGroup>
-        <EuiFlexItem grow={1}>
-          <DatasourceInputVarField
-            varDef={{
-              name: 'name',
-              title: i18n.translate(
-                'xpack.ingestManager.createDatasource.stepConfigure.datasourceNameInputLabel',
-                {
-                  defaultMessage: 'Data source name',
-                }
-              ),
-              type: 'text',
-              required: true,
-            }}
-            value={datasource.name}
-            onChange={(newValue: any) => {
-              updateDatasource({
-                name: newValue,
-              });
-            }}
-            errors={validationResults!.name}
-            forceShowErrors={submitAttempted}
-          />
-        </EuiFlexItem>
-        <EuiFlexItem grow={1}>
-          <DatasourceInputVarField
-            varDef={{
-              name: 'description',
-              title: i18n.translate(
-                'xpack.ingestManager.createDatasource.stepConfigure.datasourceDescriptionInputLabel',
-                {
-                  defaultMessage: 'Description',
-                }
-              ),
-              type: 'text',
-              required: false,
-            }}
-            value={datasource.description}
-            onChange={(newValue: any) => {
-              updateDatasource({
-                description: newValue,
-              });
-            }}
-            errors={validationResults!.description}
-            forceShowErrors={submitAttempted}
-          />
-        </EuiFlexItem>
-      </EuiFlexGroup>
-      <EuiSpacer size="m" />
-      <EuiButtonEmpty
-        flush="left"
-        size="xs"
-        iconType={isShowingAdvancedDefine ? 'arrowUp' : 'arrowDown'}
-        onClick={() => setIsShowingAdvancedDefine(!isShowingAdvancedDefine)}
-      >
-        <FormattedMessage
-          id="xpack.ingestManager.createDatasource.stepConfigure.advancedOptionsToggleLinkText"
-          defaultMessage="Advanced options"
-        />
-      </EuiButtonEmpty>
-      {/* Todo: Populate list of existing namespaces */}
-      {isShowingAdvancedDefine ? (
-        <Fragment>
-          <EuiSpacer size="m" />
-          <EuiFlexGroup>
-            <EuiFlexItem grow={1}>
-              <EuiFormRow
-                label={
-                  <FormattedMessage
-                    id="xpack.ingestManager.createDatasource.stepConfigure.datasourceNamespaceInputLabel"
-                    defaultMessage="Namespace"
-                  />
-                }
-              >
-                <EuiComboBox
-                  noSuggestions
-                  singleSelection={true}
-                  selectedOptions={datasource.namespace ? [{ label: datasource.namespace }] : []}
-                  onCreateOption={(newNamespace: string) => {
-                    updateDatasource({
-                      namespace: newNamespace,
-                    });
-                  }}
-                  onChange={(newNamespaces: Array<{ label: string }>) => {
-                    updateDatasource({
-                      namespace: newNamespaces.length ? newNamespaces[0].label : '',
-                    });
-                  }}
-                />
-              </EuiFormRow>
-            </EuiFlexItem>
-            <EuiFlexItem grow={1} />
-          </EuiFlexGroup>
-        </Fragment>
-      ) : null}
-    </EuiPanel>
-  );
-
   // Step B, configure inputs (and their streams)
   // Assume packages only export one datasource for now
   const renderConfigureInputs = () =>
@@ -252,41 +139,10 @@ export const StepConfigureDatasource: React.FunctionComponent<{
 
   return validationResults ? (
     <EuiFlexGroup direction="column" gutterSize="none">
-      <EuiFlexItem>
-        <EuiFlexGroup direction="column" gutterSize="none">
-          <EuiFlexItem>
-            <EuiFlexGroup justifyContent="flexEnd">
-              <EuiFlexItem grow={false}>{backLink}</EuiFlexItem>
-            </EuiFlexGroup>
-          </EuiFlexItem>
-          <EuiFlexItem>
-            <EuiSteps
-              steps={[
-                {
-                  title: i18n.translate(
-                    'xpack.ingestManager.createDatasource.stepConfigure.defineDatasourceTitle',
-                    {
-                      defaultMessage: 'Define your datasource',
-                    }
-                  ),
-                  children: renderDefineDatasource(),
-                },
-                {
-                  title: i18n.translate(
-                    'xpack.ingestManager.createDatasource.stepConfigure.chooseDataTitle',
-                    {
-                      defaultMessage: 'Choose the data you want to collect',
-                    }
-                  ),
-                  children: renderConfigureInputs(),
-                },
-              ]}
-            />
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
+      <EuiFlexItem>{renderConfigureInputs()}</EuiFlexItem>
       {hasErrors && submitAttempted ? (
         <EuiFlexItem>
+          <EuiSpacer size="m" />
           <EuiCallOut
             title={i18n.translate(
               'xpack.ingestManager.createDatasource.stepConfigure.validationErrorTitle',
@@ -306,36 +162,6 @@ export const StepConfigureDatasource: React.FunctionComponent<{
           <EuiSpacer size="m" />
         </EuiFlexItem>
       ) : null}
-      <EuiFlexItem>
-        <EuiFlexGroup justifyContent="flexEnd">
-          <EuiFlexItem grow={false}>
-            <EuiButtonEmpty href={cancelUrl}>
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.cancelLinkText"
-                defaultMessage="Cancel"
-              />
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>
-            <EuiButton
-              fill
-              iconType="arrowRight"
-              iconSide="right"
-              onClick={() => {
-                setSubmitAttempted(true);
-                if (!hasErrors) {
-                  onNext();
-                }
-              }}
-            >
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.continueButtonText"
-                defaultMessage="Continue"
-              />
-            </EuiButton>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
     </EuiFlexGroup>
   ) : (
     <Loading />
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_define_datasource.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_define_datasource.tsx
new file mode 100644
index 0000000000000..792389381eaf0
--- /dev/null
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_define_datasource.tsx
@@ -0,0 +1,165 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React, { useEffect, useState, Fragment } from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+import {
+  EuiFlexGrid,
+  EuiFlexItem,
+  EuiFormRow,
+  EuiFieldText,
+  EuiButtonEmpty,
+  EuiSpacer,
+  EuiText,
+  EuiComboBox,
+} from '@elastic/eui';
+import { AgentConfig, PackageInfo, Datasource, NewDatasource } from '../../../types';
+import { packageToConfigDatasourceInputs } from '../../../services';
+
+export const StepDefineDatasource: React.FunctionComponent<{
+  agentConfig: AgentConfig;
+  packageInfo: PackageInfo;
+  datasource: NewDatasource;
+  updateDatasource: (fields: Partial<NewDatasource>) => void;
+}> = ({ agentConfig, packageInfo, datasource, updateDatasource }) => {
+  // Form show/hide states
+  const [isShowingAdvancedDefine, setIsShowingAdvancedDefine] = useState<boolean>(false);
+
+  // Update datasource's package and config info
+  useEffect(() => {
+    const dsPackage = datasource.package;
+    const currentPkgKey = dsPackage ? `${dsPackage.name}-${dsPackage.version}` : '';
+    const pkgKey = `${packageInfo.name}-${packageInfo.version}`;
+
+    // If package has changed, create shell datasource with input&stream values based on package info
+    if (currentPkgKey !== pkgKey) {
+      // Existing datasources on the agent config using the package name, retrieve highest number appended to datasource name
+      const dsPackageNamePattern = new RegExp(`${packageInfo.name}-(\\d+)`);
+      const dsWithMatchingNames = (agentConfig.datasources as Datasource[])
+        .filter(ds => Boolean(ds.name.match(dsPackageNamePattern)))
+        .map(ds => parseInt(ds.name.match(dsPackageNamePattern)![1], 10))
+        .sort();
+
+      updateDatasource({
+        name: `${packageInfo.name}-${
+          dsWithMatchingNames.length ? dsWithMatchingNames[dsWithMatchingNames.length - 1] + 1 : 1
+        }`,
+        package: {
+          name: packageInfo.name,
+          title: packageInfo.title,
+          version: packageInfo.version,
+        },
+        inputs: packageToConfigDatasourceInputs(packageInfo),
+      });
+    }
+
+    // If agent config has changed, update datasource's config ID and namespace
+    if (datasource.config_id !== agentConfig.id) {
+      updateDatasource({
+        config_id: agentConfig.id,
+        namespace: agentConfig.namespace,
+      });
+    }
+  }, [datasource.package, datasource.config_id, agentConfig, packageInfo, updateDatasource]);
+
+  return (
+    <>
+      <EuiFlexGrid columns={2}>
+        <EuiFlexItem>
+          <EuiFormRow
+            label={
+              <FormattedMessage
+                id="xpack.ingestManager.createDatasource.stepConfigure.datasourceNameInputLabel"
+                defaultMessage="Data source name"
+              />
+            }
+          >
+            <EuiFieldText
+              value={datasource.name}
+              onChange={e =>
+                updateDatasource({
+                  name: e.target.value,
+                })
+              }
+            />
+          </EuiFormRow>
+        </EuiFlexItem>
+        <EuiFlexItem>
+          <EuiFormRow
+            label={
+              <FormattedMessage
+                id="xpack.ingestManager.createDatasource.stepConfigure.datasourceDescriptionInputLabel"
+                defaultMessage="Description"
+              />
+            }
+            labelAppend={
+              <EuiText size="xs" color="subdued">
+                <FormattedMessage
+                  id="xpack.ingestManager.createDatasource.stepConfigure.inputVarFieldOptionalLabel"
+                  defaultMessage="Optional"
+                />
+              </EuiText>
+            }
+          >
+            <EuiFieldText
+              value={datasource.description}
+              onChange={e =>
+                updateDatasource({
+                  description: e.target.value,
+                })
+              }
+            />
+          </EuiFormRow>
+        </EuiFlexItem>
+      </EuiFlexGrid>
+      <EuiSpacer size="m" />
+      <EuiButtonEmpty
+        flush="left"
+        size="xs"
+        iconType={isShowingAdvancedDefine ? 'arrowUp' : 'arrowDown'}
+        onClick={() => setIsShowingAdvancedDefine(!isShowingAdvancedDefine)}
+      >
+        <FormattedMessage
+          id="xpack.ingestManager.createDatasource.stepConfigure.advancedOptionsToggleLinkText"
+          defaultMessage="Advanced options"
+        />
+      </EuiButtonEmpty>
+      {/* Todo: Populate list of existing namespaces */}
+      {isShowingAdvancedDefine ? (
+        <Fragment>
+          <EuiSpacer size="m" />
+          <EuiFlexGrid columns={2}>
+            <EuiFlexItem>
+              <EuiFormRow
+                label={
+                  <FormattedMessage
+                    id="xpack.ingestManager.createDatasource.stepConfigure.datasourceNamespaceInputLabel"
+                    defaultMessage="Namespace"
+                  />
+                }
+              >
+                <EuiComboBox
+                  noSuggestions
+                  singleSelection={true}
+                  selectedOptions={datasource.namespace ? [{ label: datasource.namespace }] : []}
+                  onCreateOption={(newNamespace: string) => {
+                    updateDatasource({
+                      namespace: newNamespace,
+                    });
+                  }}
+                  onChange={(newNamespaces: Array<{ label: string }>) => {
+                    updateDatasource({
+                      namespace: newNamespaces.length ? newNamespaces[0].label : '',
+                    });
+                  }}
+                />
+              </EuiFormRow>
+            </EuiFlexItem>
+          </EuiFlexGrid>
+        </Fragment>
+      ) : null}
+    </>
+  );
+};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx
deleted file mode 100644
index 20af5954c1436..0000000000000
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import React, { Fragment, useState, useEffect } from 'react';
-import { i18n } from '@kbn/i18n';
-import { FormattedMessage } from '@kbn/i18n/react';
-import {
-  EuiFlexGroup,
-  EuiFlexItem,
-  EuiButtonEmpty,
-  EuiButton,
-  EuiTitle,
-  EuiCallOut,
-  EuiText,
-  EuiCheckbox,
-  EuiTabbedContent,
-  EuiCodeBlock,
-  EuiSpacer,
-} from '@elastic/eui';
-import { dump } from 'js-yaml';
-import { NewDatasource, AgentConfig } from '../../../types';
-import { useConfig, sendGetAgentStatus } from '../../../hooks';
-import { storedDatasourceToAgentDatasource } from '../../../services';
-
-const KEYS_TO_SINK = ['inputs', 'streams'];
-
-export const StepReviewDatasource: React.FunctionComponent<{
-  agentConfig: AgentConfig;
-  datasource: NewDatasource;
-  backLink: JSX.Element;
-  cancelUrl: string;
-  onSubmit: () => void;
-  isSubmitLoading: boolean;
-}> = ({ agentConfig, datasource, backLink, cancelUrl, onSubmit, isSubmitLoading }) => {
-  // Agent count info states
-  const [agentCount, setAgentCount] = useState<number>(0);
-  const [agentCountChecked, setAgentCountChecked] = useState<boolean>(false);
-
-  // Config information
-  const {
-    fleet: { enabled: isFleetEnabled },
-  } = useConfig();
-
-  // Retrieve agent count
-  useEffect(() => {
-    const getAgentCount = async () => {
-      const { data } = await sendGetAgentStatus({ configId: agentConfig.id });
-      if (data?.results.total) {
-        setAgentCount(data.results.total);
-      }
-    };
-
-    if (isFleetEnabled) {
-      getAgentCount();
-    }
-  }, [agentConfig.id, isFleetEnabled]);
-
-  const showAgentDisclaimer = isFleetEnabled && agentCount;
-  const fullAgentDatasource = storedDatasourceToAgentDatasource(datasource);
-
-  return (
-    <EuiFlexGroup direction="column">
-      <EuiFlexItem>
-        <EuiFlexGroup justifyContent="spaceBetween">
-          <EuiFlexItem grow={false}>
-            <EuiTitle size="s">
-              <h3>
-                <FormattedMessage
-                  id="xpack.ingestManager.createDatasource.stepReview.reviewTitle"
-                  defaultMessage="Review changes"
-                />
-              </h3>
-            </EuiTitle>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>{backLink}</EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
-
-      {/* Agents affected warning */}
-      {showAgentDisclaimer ? (
-        <EuiFlexItem>
-          <EuiCallOut
-            title={
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.stepReview.agentsAffectedCalloutTitle"
-                defaultMessage="This action will affect {count, plural, one {# agent} other {# agents}}"
-                values={{
-                  count: agentCount,
-                }}
-              />
-            }
-          >
-            <EuiText>
-              <p>
-                <FormattedMessage
-                  id="xpack.ingestManager.createDatasource.stepReview.agentsAffectedCalloutText"
-                  defaultMessage="Fleet has detected that the selected agent configuration, {configName} is already in use by some your agents. As a result of this action, Fleet will update all agents that are enrolled with this configuration."
-                  values={{
-                    configName: <strong>{agentConfig.name}</strong>,
-                  }}
-                />
-              </p>
-            </EuiText>
-          </EuiCallOut>
-        </EuiFlexItem>
-      ) : null}
-
-      {/* Preview and YAML view */}
-      {/* TODO: Implement preview tab */}
-      <EuiFlexItem>
-        <EuiTabbedContent
-          tabs={[
-            {
-              id: 'yaml',
-              name: i18n.translate('xpack.ingestManager.agentConfigInfo.yamlTabName', {
-                defaultMessage: 'YAML',
-              }),
-              content: (
-                <Fragment>
-                  <EuiSpacer size="s" />
-                  <EuiCodeBlock language="yaml" isCopyable overflowHeight={450}>
-                    {dump(fullAgentDatasource, {
-                      sortKeys: (a: string, b: string) => {
-                        // Make YAML output prettier by sinking certain fields
-                        if (KEYS_TO_SINK.indexOf(a) > -1) {
-                          return 1;
-                        }
-                        if (KEYS_TO_SINK.indexOf(b) > -1) {
-                          return -1;
-                        }
-                        return 0;
-                      },
-                    })}
-                  </EuiCodeBlock>
-                </Fragment>
-              ),
-            },
-          ]}
-        />
-      </EuiFlexItem>
-
-      {/* Confirm agents affected */}
-      {showAgentDisclaimer ? (
-        <EuiFlexItem>
-          <EuiFlexGroup direction="column" gutterSize="s">
-            <EuiFlexItem>
-              <EuiTitle size="xs">
-                <h4>
-                  <FormattedMessage
-                    id="xpack.ingestManager.createDatasource.stepReview.confirmAgentDisclaimerTitle"
-                    defaultMessage="Confirm your decision"
-                  />
-                </h4>
-              </EuiTitle>
-            </EuiFlexItem>
-            <EuiFlexItem>
-              <EuiCheckbox
-                id="CreateDatasourceAgentDisclaimer"
-                label={
-                  <FormattedMessage
-                    id="xpack.ingestManager.createDatasource.stepReview.confirmAgentDisclaimerText"
-                    defaultMessage="I understand that this action will update all agents that are enrolled with this configuration."
-                  />
-                }
-                checked={agentCountChecked}
-                onChange={e => setAgentCountChecked(e.target.checked)}
-              />
-            </EuiFlexItem>
-          </EuiFlexGroup>
-        </EuiFlexItem>
-      ) : null}
-
-      <EuiFlexItem>
-        <EuiFlexGroup justifyContent="flexEnd">
-          <EuiFlexItem grow={false}>
-            <EuiButtonEmpty href={cancelUrl}>
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.cancelLinkText"
-                defaultMessage="Cancel"
-              />
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>
-            <EuiButton
-              fill
-              onClick={() => onSubmit()}
-              isLoading={isSubmitLoading}
-              disabled={isSubmitLoading || Boolean(showAgentDisclaimer && !agentCountChecked)}
-            >
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.addDatasourceButtonText"
-                defaultMessage="Add datasource to configuration"
-              />
-            </EuiButton>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
-    </EuiFlexGroup>
-  );
-};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_config.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_config.tsx
index 2ddfc170069a1..6cbe56e628903 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_config.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_config.tsx
@@ -6,19 +6,8 @@
 import React, { useEffect, useState, Fragment } from 'react';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-import {
-  EuiButtonEmpty,
-  EuiButton,
-  EuiFlexGroup,
-  EuiFlexItem,
-  EuiTitle,
-  EuiSelectable,
-  EuiSpacer,
-  EuiTextColor,
-} from '@elastic/eui';
+import { EuiFlexGroup, EuiFlexItem, EuiSelectable, EuiSpacer, EuiTextColor } from '@elastic/eui';
 import { Error } from '../../../components';
-import { AGENT_CONFIG_PATH } from '../../../constants';
-import { useCapabilities, useLink } from '../../../hooks';
 import { AgentConfig, PackageInfo, GetAgentConfigsResponseItem } from '../../../types';
 import { useGetPackageInfoByKey, useGetAgentConfigs, sendGetOneAgentConfig } from '../../../hooks';
 
@@ -27,20 +16,13 @@ export const StepSelectConfig: React.FunctionComponent<{
   updatePackageInfo: (packageInfo: PackageInfo | undefined) => void;
   agentConfig: AgentConfig | undefined;
   updateAgentConfig: (config: AgentConfig | undefined) => void;
-  cancelUrl: string;
-  onNext: () => void;
-}> = ({ pkgkey, updatePackageInfo, agentConfig, updateAgentConfig, cancelUrl, onNext }) => {
-  const hasWriteCapabilites = useCapabilities().write;
+}> = ({ pkgkey, updatePackageInfo, agentConfig, updateAgentConfig }) => {
   // Selected config state
   const [selectedConfigId, setSelectedConfigId] = useState<string | undefined>(
     agentConfig ? agentConfig.id : undefined
   );
-  const [selectedConfigLoading, setSelectedConfigLoading] = useState<boolean>(false);
   const [selectedConfigError, setSelectedConfigError] = useState<Error>();
 
-  // Todo: replace with create agent config flyout
-  const CREATE_NEW_CONFIG_URI = useLink(AGENT_CONFIG_PATH);
-
   // Fetch package info
   const { data: packageInfoData, error: packageInfoError } = useGetPackageInfoByKey(pkgkey);
 
@@ -70,9 +52,7 @@ export const StepSelectConfig: React.FunctionComponent<{
   useEffect(() => {
     const fetchAgentConfigInfo = async () => {
       if (selectedConfigId) {
-        setSelectedConfigLoading(true);
         const { data, error } = await sendGetOneAgentConfig(selectedConfigId);
-        setSelectedConfigLoading(false);
         if (error) {
           setSelectedConfigError(error);
           updateAgentConfig(undefined);
@@ -122,33 +102,6 @@ export const StepSelectConfig: React.FunctionComponent<{
 
   return (
     <EuiFlexGroup direction="column">
-      <EuiFlexItem>
-        <EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
-          <EuiFlexItem grow={false}>
-            <EuiTitle size="s">
-              <h3>
-                <FormattedMessage
-                  id="xpack.ingestManager.createDatasource.StepSelectConfig.selectAgentConfigTitle"
-                  defaultMessage="Select an agent configuration"
-                />
-              </h3>
-            </EuiTitle>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>
-            <EuiButtonEmpty
-              isDisabled={!hasWriteCapabilites}
-              iconType="plusInCircle"
-              href={CREATE_NEW_CONFIG_URI}
-              size="s"
-            >
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.StepSelectConfig.createNewConfigButtonText"
-                defaultMessage="Create new configuration"
-              />
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
       <EuiFlexItem>
         <EuiSelectable
           searchable
@@ -227,33 +180,6 @@ export const StepSelectConfig: React.FunctionComponent<{
           />
         </EuiFlexItem>
       ) : null}
-      <EuiFlexItem>
-        <EuiFlexGroup justifyContent="flexEnd">
-          <EuiFlexItem grow={false}>
-            <EuiButtonEmpty href={cancelUrl}>
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.cancelLinkText"
-                defaultMessage="Cancel"
-              />
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>
-            <EuiButton
-              fill
-              iconType="arrowRight"
-              iconSide="right"
-              isLoading={selectedConfigLoading}
-              disabled={!selectedConfigId || !!selectedConfigError || selectedConfigLoading}
-              onClick={() => onNext()}
-            >
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.continueButtonText"
-                defaultMessage="Continue"
-              />
-            </EuiButton>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
     </EuiFlexGroup>
   );
 };
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx
index 496e1d3c0fd7b..8dabb3bc98110 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx
@@ -6,15 +6,7 @@
 import React, { useEffect, useState, Fragment } from 'react';
 import { i18n } from '@kbn/i18n';
 import { FormattedMessage } from '@kbn/i18n/react';
-import {
-  EuiButtonEmpty,
-  EuiButton,
-  EuiFlexGroup,
-  EuiFlexItem,
-  EuiTitle,
-  EuiSelectable,
-  EuiSpacer,
-} from '@elastic/eui';
+import { EuiFlexGroup, EuiFlexItem, EuiSelectable, EuiSpacer } from '@elastic/eui';
 import { Error } from '../../../components';
 import { AgentConfig, PackageInfo } from '../../../types';
 import { useGetOneAgentConfig, useGetPackages, sendGetPackageInfoByKey } from '../../../hooks';
@@ -25,14 +17,11 @@ export const StepSelectPackage: React.FunctionComponent<{
   updateAgentConfig: (config: AgentConfig | undefined) => void;
   packageInfo?: PackageInfo;
   updatePackageInfo: (packageInfo: PackageInfo | undefined) => void;
-  cancelUrl: string;
-  onNext: () => void;
-}> = ({ agentConfigId, updateAgentConfig, packageInfo, updatePackageInfo, cancelUrl, onNext }) => {
+}> = ({ agentConfigId, updateAgentConfig, packageInfo, updatePackageInfo }) => {
   // Selected package state
   const [selectedPkgKey, setSelectedPkgKey] = useState<string | undefined>(
     packageInfo ? `${packageInfo.name}-${packageInfo.version}` : undefined
   );
-  const [selectedPkgLoading, setSelectedPkgLoading] = useState<boolean>(false);
   const [selectedPkgError, setSelectedPkgError] = useState<Error>();
 
   // Fetch agent config info
@@ -57,9 +46,7 @@ export const StepSelectPackage: React.FunctionComponent<{
   useEffect(() => {
     const fetchPackageInfo = async () => {
       if (selectedPkgKey) {
-        setSelectedPkgLoading(true);
         const { data, error } = await sendGetPackageInfoByKey(selectedPkgKey);
-        setSelectedPkgLoading(false);
         if (error) {
           setSelectedPkgError(error);
           updatePackageInfo(undefined);
@@ -109,16 +96,6 @@ export const StepSelectPackage: React.FunctionComponent<{
 
   return (
     <EuiFlexGroup direction="column">
-      <EuiFlexItem>
-        <EuiTitle size="s">
-          <h3>
-            <FormattedMessage
-              id="xpack.ingestManager.createDatasource.stepSelectPackage.selectPackageTitle"
-              defaultMessage="Select integration"
-            />
-          </h3>
-        </EuiTitle>
-      </EuiFlexItem>
       <EuiFlexItem>
         <EuiSelectable
           searchable
@@ -186,33 +163,6 @@ export const StepSelectPackage: React.FunctionComponent<{
           />
         </EuiFlexItem>
       ) : null}
-      <EuiFlexItem>
-        <EuiFlexGroup justifyContent="flexEnd">
-          <EuiFlexItem grow={false}>
-            <EuiButtonEmpty href={cancelUrl}>
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.cancelLinkText"
-                defaultMessage="Cancel"
-              />
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>
-            <EuiButton
-              fill
-              iconType="arrowRight"
-              iconSide="right"
-              isLoading={selectedPkgLoading}
-              disabled={!selectedPkgKey || !!selectedPkgError || selectedPkgLoading}
-              onClick={() => onNext()}
-            >
-              <FormattedMessage
-                id="xpack.ingestManager.createDatasource.continueButtonText"
-                defaultMessage="Continue"
-              />
-            </EuiButton>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </EuiFlexItem>
     </EuiFlexGroup>
   );
 };
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx
index 1bc20c2baf660..a0244c601cd96 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx
@@ -86,7 +86,7 @@ export const EnrollmentInstructions: React.FunctionComponent<Props> = ({ selecte
           steps={[
             {
               title: i18n.translate('xpack.ingestManager.agentEnrollment.stepSetupAgents', {
-                defaultMessage: 'Setup Beats agent',
+                defaultMessage: 'Setup Elastic agent',
               }),
               children: (
                 <ShellEnrollmentInstructions
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx
index 22314b6231d1e..d363c472f2305 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx
@@ -364,7 +364,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
         <h2>
           <FormattedMessage
             id="xpack.ingestManager.agentList.noAgentsPrompt"
-            defaultMessage="No agents installed"
+            defaultMessage="No agents enrolled"
           />
         </h2>
       }
@@ -373,7 +373,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
           <EuiButton fill iconType="plusInCircle" onClick={() => setIsEnrollmentFlyoutOpen(true)}>
             <FormattedMessage
               id="xpack.ingestManager.agentList.addButton"
-              defaultMessage="Install new agent"
+              defaultMessage="Enroll new agent"
             />
           </EuiButton>
         ) : null
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index e579830bad203..3cebde793a085 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -8283,7 +8283,6 @@
     "xpack.ingestManager.agentConfigForm.systemMonitoringFieldLabel": "オプション",
     "xpack.ingestManager.agentConfigForm.systemMonitoringText": "システムメトリックを収集",
     "xpack.ingestManager.agentConfigForm.systemMonitoringTooltipText": "このオプションを有効にすると、システムメトリックと情報を収集するデータソースで構成をブートストラップできます。",
-    "xpack.ingestManager.agentConfigInfo.yamlTabName": "YAML",
     "xpack.ingestManager.agentConfigList.actionsColumnTitle": "アクション",
     "xpack.ingestManager.agentConfigList.actionsMenuText": "開く",
     "xpack.ingestManager.agentConfigList.addButton": "エージェント構成を作成",
@@ -8421,21 +8420,14 @@
     "xpack.ingestManager.createAgentConfig.flyoutTitleDescription": "エージェント構成は、エージェントのグループ全体にわたる設定を管理する目的で使用されます。エージェント構成にデータソースを追加すると、エージェントで収集するデータを指定できます。エージェント構成の編集時には、フリートを使用して、指定したエージェントのグループに更新をデプロイできます。",
     "xpack.ingestManager.createAgentConfig.submitButtonLabel": "エージェント構成を作成",
     "xpack.ingestManager.createAgentConfig.successNotificationTitle": "エージェント構成「{name}」を作成しました",
-    "xpack.ingestManager.createDatasource.addDatasourceButtonText": "データソースに構成を追加",
     "xpack.ingestManager.createDatasource.agentConfigurationNameLabel": "構成",
     "xpack.ingestManager.createDatasource.cancelLinkText": "キャンセル",
-    "xpack.ingestManager.createDatasource.changeConfigLinkText": "構成を変更",
-    "xpack.ingestManager.createDatasource.changePackageLinkText": "パッケージを変更",
-    "xpack.ingestManager.createDatasource.continueButtonText": "続行",
-    "xpack.ingestManager.createDatasource.editDatasourceLinkText": "データソースを編集",
     "xpack.ingestManager.createDatasource.packageNameLabel": "パッケージ",
     "xpack.ingestManager.createDatasource.pageTitle": "データソースを作成",
     "xpack.ingestManager.createDatasource.stepConfigure.advancedOptionsToggleLinkText": "高度なオプション",
-    "xpack.ingestManager.createDatasource.stepConfigure.chooseDataTitle": "収集したいデータを選択してください",
     "xpack.ingestManager.createDatasource.stepConfigure.datasourceDescriptionInputLabel": "説明",
     "xpack.ingestManager.createDatasource.stepConfigure.datasourceNameInputLabel": "データソース名",
     "xpack.ingestManager.createDatasource.stepConfigure.datasourceNamespaceInputLabel": "名前空間",
-    "xpack.ingestManager.createDatasource.stepConfigure.defineDatasourceTitle": "データソースを定義する",
     "xpack.ingestManager.createDatasource.stepConfigure.hideStreamsAriaLabel": "{type} ストリームを隠す",
     "xpack.ingestManager.createDatasource.stepConfigure.inputSettingsDescription": "次の設定はすべてのストリームに適用されます。",
     "xpack.ingestManager.createDatasource.stepConfigure.inputSettingsTitle": "設定",
@@ -8444,27 +8436,15 @@
     "xpack.ingestManager.createDatasource.stepConfigure.showStreamsAriaLabel": "{type} ストリームを表示",
     "xpack.ingestManager.createDatasource.stepConfigure.streamsEnabledCountText": "{count} / {total, plural, one {# ストリーム} other {# ストリーム}}が有効です",
     "xpack.ingestManager.createDatasource.stepConfigure.toggleAdvancedOptionsButtonText": "高度なオプション",
-    "xpack.ingestManager.createDatasource.stepConfigureDatasourceLabel": "構成データソース",
-    "xpack.ingestManager.createDatasource.stepReview.agentsAffectedCalloutText": "選択されたエージェント構成 {configName} が一部のエージェントで既に使用されていることをフリートが検出しました。このアクションの結果として、フリートはこの構成に登録されているすべてのエージェントを更新します。",
-    "xpack.ingestManager.createDatasource.stepReview.agentsAffectedCalloutTitle": "このアクションは {count, plural, one {# エージェント} other {# エージェント}}に影響します",
-    "xpack.ingestManager.createDatasource.stepReview.confirmAgentDisclaimerText": "このアクションによって、この構成に登録されているすべてのエージェントが更新されることを理解しています。",
-    "xpack.ingestManager.createDatasource.stepReview.confirmAgentDisclaimerTitle": "意思決定を確認",
-    "xpack.ingestManager.createDatasource.stepReview.reviewTitle": "変更の見直し",
-    "xpack.ingestManager.createDatasource.stepReviewLabel": "見直し",
     "xpack.ingestManager.createDatasource.StepSelectConfig.agentConfigAgentsCountText": "{count, plural, one {# エージェント} other {# エージェント}}",
-    "xpack.ingestManager.createDatasource.StepSelectConfig.createNewConfigButtonText": "新しい構成を作成",
     "xpack.ingestManager.createDatasource.StepSelectConfig.errorLoadingAgentConfigsTitle": "エージェント構成の読み込みエラー",
     "xpack.ingestManager.createDatasource.StepSelectConfig.errorLoadingPackageTitle": "パッケージ情報の読み込みエラー",
     "xpack.ingestManager.createDatasource.StepSelectConfig.errorLoadingSelectedAgentConfigTitle": "選択したエージェント構成の読み込みエラー",
     "xpack.ingestManager.createDatasource.StepSelectConfig.filterAgentConfigsInputPlaceholder": "エージェント構成の検索",
-    "xpack.ingestManager.createDatasource.StepSelectConfig.selectAgentConfigTitle": "エージェント構成を選択する",
-    "xpack.ingestManager.createDatasource.stepSelectConfigLabel": "構成を選択",
     "xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingConfigTitle": "エージェント構成情報の読み込みエラー",
     "xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingPackagesTitle": "パッケージの読み込みエラー",
     "xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingSelectedPackageTitle": "選択したパッケージの読み込みエラー",
     "xpack.ingestManager.createDatasource.stepSelectPackage.filterPackagesInputPlaceholder": "パッケージの検索",
-    "xpack.ingestManager.createDatasource.stepSelectPackage.selectPackageTitle": "パッケージを選択する",
-    "xpack.ingestManager.createDatasource.stepSelectPackageLabel": "パッケージを選択",
     "xpack.ingestManager.deleteAgentConfigs.confirmModal.affectedAgentsMessage": "{agentsCount, plural, one {# エージェントを} other {# エージェントを}}{agentConfigsCount, plural, one {このエージェント構成に} other {これらのエージェント構成に}}割り当てました。 {agentsCount, plural, one {このエージェント} other {これらのエージェント}}の登録が解除されます。",
     "xpack.ingestManager.deleteAgentConfigs.confirmModal.cancelButtonLabel": "キャンセル",
     "xpack.ingestManager.deleteAgentConfigs.confirmModal.confirmAndReassignButtonLabel": "{agentConfigsCount, plural, one {エージェント構成} other {エージェント構成}} and unenroll {agentsCount, plural, one {エージェント} other {エージェント}} を削除",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 75f48fb11823a..1daf66117e948 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -8286,7 +8286,6 @@
     "xpack.ingestManager.agentConfigForm.systemMonitoringFieldLabel": "可选",
     "xpack.ingestManager.agentConfigForm.systemMonitoringText": "收集系统指标",
     "xpack.ingestManager.agentConfigForm.systemMonitoringTooltipText": "启用此选项可使用收集系统指标和信息的数据源启动您的配置。",
-    "xpack.ingestManager.agentConfigInfo.yamlTabName": "YAML",
     "xpack.ingestManager.agentConfigList.actionsColumnTitle": "操作",
     "xpack.ingestManager.agentConfigList.actionsMenuText": "打开",
     "xpack.ingestManager.agentConfigList.addButton": "创建代理配置",
@@ -8424,21 +8423,14 @@
     "xpack.ingestManager.createAgentConfig.flyoutTitleDescription": "代理配置用于管理整个代理组的设置。您可以将数据源添加到代理配置以指定代理收集的数据。编辑代理配置时,可以使用 Fleet 将更新部署到指定的代理组。",
     "xpack.ingestManager.createAgentConfig.submitButtonLabel": "创建代理配置",
     "xpack.ingestManager.createAgentConfig.successNotificationTitle": "代理配置“{name}”已创建",
-    "xpack.ingestManager.createDatasource.addDatasourceButtonText": "将数据源添加到配置",
     "xpack.ingestManager.createDatasource.agentConfigurationNameLabel": "配置",
     "xpack.ingestManager.createDatasource.cancelLinkText": "取消",
-    "xpack.ingestManager.createDatasource.changeConfigLinkText": "更改配置",
-    "xpack.ingestManager.createDatasource.changePackageLinkText": "更改软件包",
-    "xpack.ingestManager.createDatasource.continueButtonText": "继续",
-    "xpack.ingestManager.createDatasource.editDatasourceLinkText": "编辑数据源",
     "xpack.ingestManager.createDatasource.packageNameLabel": "软件包",
     "xpack.ingestManager.createDatasource.pageTitle": "创建数据源",
     "xpack.ingestManager.createDatasource.stepConfigure.advancedOptionsToggleLinkText": "高级选项",
-    "xpack.ingestManager.createDatasource.stepConfigure.chooseDataTitle": "选择要收集的数据",
     "xpack.ingestManager.createDatasource.stepConfigure.datasourceDescriptionInputLabel": "描述",
     "xpack.ingestManager.createDatasource.stepConfigure.datasourceNameInputLabel": "数据源名称",
     "xpack.ingestManager.createDatasource.stepConfigure.datasourceNamespaceInputLabel": "命名空间",
-    "xpack.ingestManager.createDatasource.stepConfigure.defineDatasourceTitle": "定义您的数据源",
     "xpack.ingestManager.createDatasource.stepConfigure.hideStreamsAriaLabel": "隐藏 {type} 流",
     "xpack.ingestManager.createDatasource.stepConfigure.inputSettingsDescription": "以下设置适用于所有流。",
     "xpack.ingestManager.createDatasource.stepConfigure.inputSettingsTitle": "设置",
@@ -8447,27 +8439,15 @@
     "xpack.ingestManager.createDatasource.stepConfigure.showStreamsAriaLabel": "显示 {type} 流",
     "xpack.ingestManager.createDatasource.stepConfigure.streamsEnabledCountText": "{count} / {total, plural, one {# 个流} other {# 个流}}已启用",
     "xpack.ingestManager.createDatasource.stepConfigure.toggleAdvancedOptionsButtonText": "高级选项",
-    "xpack.ingestManager.createDatasource.stepConfigureDatasourceLabel": "配置数据源",
-    "xpack.ingestManager.createDatasource.stepReview.agentsAffectedCalloutText": "Fleet 检测到所选代理配置 {configName} 已由您的部分代理使用。此操作的结果是,Fleet 将更新用此配置进行注册的所有代理。",
-    "xpack.ingestManager.createDatasource.stepReview.agentsAffectedCalloutTitle": "此操作将影响 {count, plural, one {# 个代理} other {# 个代理}}",
-    "xpack.ingestManager.createDatasource.stepReview.confirmAgentDisclaimerText": "我理解此操作将更新注册到此配置的所有代理。",
-    "xpack.ingestManager.createDatasource.stepReview.confirmAgentDisclaimerTitle": "确认您的决定",
-    "xpack.ingestManager.createDatasource.stepReview.reviewTitle": "复查更改",
-    "xpack.ingestManager.createDatasource.stepReviewLabel": "复查",
     "xpack.ingestManager.createDatasource.StepSelectConfig.agentConfigAgentsCountText": "{count, plural, one {# 个代理} other {# 个代理}}",
-    "xpack.ingestManager.createDatasource.StepSelectConfig.createNewConfigButtonText": "创建新配置",
     "xpack.ingestManager.createDatasource.StepSelectConfig.errorLoadingAgentConfigsTitle": "加载代理配置时出错",
     "xpack.ingestManager.createDatasource.StepSelectConfig.errorLoadingPackageTitle": "加载软件包信息时出错",
     "xpack.ingestManager.createDatasource.StepSelectConfig.errorLoadingSelectedAgentConfigTitle": "加载选定代理配置时出错",
     "xpack.ingestManager.createDatasource.StepSelectConfig.filterAgentConfigsInputPlaceholder": "搜索代理配置",
-    "xpack.ingestManager.createDatasource.StepSelectConfig.selectAgentConfigTitle": "选择代理配置",
-    "xpack.ingestManager.createDatasource.stepSelectConfigLabel": "选择配置",
     "xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingConfigTitle": "加载代理配置信息时出错",
     "xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingPackagesTitle": "加载软件包时出错",
     "xpack.ingestManager.createDatasource.stepSelectPackage.errorLoadingSelectedPackageTitle": "加载选定软件包时出错",
     "xpack.ingestManager.createDatasource.stepSelectPackage.filterPackagesInputPlaceholder": "搜索软件包",
-    "xpack.ingestManager.createDatasource.stepSelectPackage.selectPackageTitle": "选择软件包",
-    "xpack.ingestManager.createDatasource.stepSelectPackageLabel": "选择软件包",
     "xpack.ingestManager.deleteAgentConfigs.confirmModal.affectedAgentsMessage": "{agentsCount, plural, one {# 个代理} other {# 个代理}}已分配{agentConfigsCount, plural, one {给此代理配置} other {给这些代理配置}}。将取消注册{agentsCount, plural, one {此代理} other {这些代理}}。",
     "xpack.ingestManager.deleteAgentConfigs.confirmModal.cancelButtonLabel": "取消",
     "xpack.ingestManager.deleteAgentConfigs.confirmModal.confirmAndReassignButtonLabel": "删除{agentConfigsCount, plural, one {代理配置} other {代理配置}}并取消注册{agentsCount, plural, one {代理} other {代理}}",

From d00c90510d11e4575a3453b3437221b341a7478f Mon Sep 17 00:00:00 2001
From: Robert Austin <robert.austin@elastic.co>
Date: Mon, 13 Apr 2020 11:33:14 -0400
Subject: [PATCH 78/78] Endpoint: Move files, add README, replace implicit
 `any` with stricter types. Reorganize types.  (#63262)

* Removed `FIXME` comments and references to private repos. Please use Github issues to track work
* Added a README describing the modules in `applications/endpoint`
* Removed dead code
* Moved `AppRoot` component to its own module
* Moved `applications/endpoint/services` under `store`
* Moved some exported types to `applications/endpoint/types`
* Moved all React code to `view`
* Added types in some places that were implicitly `any`
* Moved `PageId` type from common directory (where it could be shared with the server) to the public directory
---
 .../plugins/endpoint/common/generate_data.ts  |  1 -
 x-pack/plugins/endpoint/common/types.ts       |  5 --
 .../public/applications/endpoint/README.md    | 28 +++++++++
 .../endpoint/components/truncate_text.ts      | 13 ----
 .../public/applications/endpoint/index.tsx    | 51 +---------------
 .../endpoint/store/alerts/index.ts            |  1 -
 .../store/policy_details/middleware.ts        | 14 +++--
 .../endpoint/store/policy_list/middleware.ts  |  4 +-
 .../policy_list}/services/ingest.test.ts      |  2 +-
 .../policy_list}/services/ingest.ts           | 32 +++-------
 .../endpoint/store/routing/action.ts          |  4 +-
 .../public/applications/endpoint/types.ts     | 27 ++++++++-
 .../applications/endpoint/view/app_root.tsx   | 59 +++++++++++++++++++
 .../__snapshots__/link_to_app.test.tsx.snap   |  0
 .../__snapshots__/page_view.test.tsx.snap     |  0
 .../components/header_navigation.tsx}         |  7 ++-
 .../components/link_to_app.test.tsx           | 17 ++++--
 .../{ => view}/components/link_to_app.tsx     |  2 +-
 .../{ => view}/components/page_view.test.tsx  |  2 +-
 .../{ => view}/components/page_view.tsx       |  0
 .../use_navigate_to_app_event_handler.ts      |  2 +-
 .../endpoint/view/hosts/details.tsx           |  2 +-
 .../endpoint/view/hosts/index.test.tsx        |  1 -
 .../endpoint/view/policy/policy_details.tsx   |  5 +-
 .../endpoint/view/policy/policy_list.tsx      |  4 +-
 .../applications/endpoint/view/use_page_id.ts |  2 +-
 26 files changed, 161 insertions(+), 124 deletions(-)
 create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/README.md
 delete mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => store/policy_list}/services/ingest.test.ts (95%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => store/policy_list}/services/ingest.ts (77%)
 create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/app_root.tsx
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/components/__snapshots__/link_to_app.test.tsx.snap (100%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/components/__snapshots__/page_view.test.tsx.snap (100%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{components/header_nav.tsx => view/components/header_navigation.tsx} (90%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/components/link_to_app.test.tsx (86%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/components/link_to_app.tsx (96%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/components/page_view.test.tsx (96%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/components/page_view.tsx (100%)
 rename x-pack/plugins/endpoint/public/applications/endpoint/{ => view}/hooks/use_navigate_to_app_event_handler.ts (96%)

diff --git a/x-pack/plugins/endpoint/common/generate_data.ts b/x-pack/plugins/endpoint/common/generate_data.ts
index 7c24bd9d77148..3f783d90e577d 100644
--- a/x-pack/plugins/endpoint/common/generate_data.ts
+++ b/x-pack/plugins/endpoint/common/generate_data.ts
@@ -7,7 +7,6 @@
 import uuid from 'uuid';
 import seedrandom from 'seedrandom';
 import { AlertEvent, EndpointEvent, HostMetadata, OSFields, HostFields } from './types';
-// FIXME: move types/model to top-level
 // eslint-disable-next-line @kbn/eslint/no-restricted-paths
 import { PolicyData } from '../public/applications/endpoint/types';
 // eslint-disable-next-line @kbn/eslint/no-restricted-paths
diff --git a/x-pack/plugins/endpoint/common/types.ts b/x-pack/plugins/endpoint/common/types.ts
index a614526d92a3f..403ca9832e191 100644
--- a/x-pack/plugins/endpoint/common/types.ts
+++ b/x-pack/plugins/endpoint/common/types.ts
@@ -375,11 +375,6 @@ export interface EndpointEvent {
 
 export type ResolverEvent = EndpointEvent | LegacyEndpointEvent;
 
-/**
- * The PageId type is used for the payload when firing userNavigatedToPage actions
- */
-export type PageId = 'alertsPage' | 'managementPage' | 'policyListPage';
-
 /**
  * Takes a @kbn/config-schema 'schema' type and returns a type that represents valid inputs.
  * Similar to `TypeOf`, but allows strings as input for `schema.number()` (which is inline
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/README.md b/x-pack/plugins/endpoint/public/applications/endpoint/README.md
new file mode 100644
index 0000000000000..25bfd615d1d2c
--- /dev/null
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/README.md
@@ -0,0 +1,28 @@
+# Endpoint application
+This application provides the user interface for the Elastic Endpoint
+
+# Architecture
+The application consists of a _view_ written in React and a _model_ written in Redux.
+
+# Modules
+We structure the modules to match the architecture. `view` contains the _view_ (all React) code. `store` contains the _model_.
+
+This section covers the conventions of each top level module.
+
+# `mocks`
+This contains helper code for unit tests.
+
+## `models`
+This contains domain models. By convention, each submodule here contains methods for a single type. Domain model classes would also live here.
+
+## `store`
+This contains the _model_ of the application. All Redux and Redux middleware code (including API interactions) happen here. This module also contains the types and interfaces defining Redux actions. Each action type or interface should be commented and if it has fields, each field should be commented. Comments should be of `tsdoc` style.
+
+## `view`
+This contains the code which renders elements to the DOM. All React code goes here.
+
+## `index.tsx`
+This exports `renderApp` which instantiates the React view with the _model_.
+
+## `types.ts`
+This contains the types and interfaces. All `export`ed types or interfaces (except ones defining Redux actions, which live in `store`) should be here. Each type or interface should have a `tsdoc` style comment. Interfaces should have `tsdoc` comments on each field and types which have fields should do the same.
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts b/x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts
deleted file mode 100644
index 83f4bc1e79317..0000000000000
--- a/x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import styled from 'styled-components';
-
-export const TruncateText = styled.div`
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-`;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx
index 82ac95160519c..a1999c056bf59 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx
@@ -6,19 +6,10 @@
 
 import * as React from 'react';
 import ReactDOM from 'react-dom';
-import { CoreStart, AppMountParameters, ScopedHistory } from 'kibana/public';
-import { FormattedMessage } from '@kbn/i18n/react';
-import { Route, Switch } from 'react-router-dom';
-import { Store } from 'redux';
+import { CoreStart, AppMountParameters } from 'kibana/public';
 import { EndpointPluginStartDependencies } from '../../plugin';
 import { appStoreFactory } from './store';
-import { AlertIndex } from './view/alerts';
-import { HostList } from './view/hosts';
-import { PolicyList } from './view/policy';
-import { PolicyDetails } from './view/policy';
-import { HeaderNavigation } from './components/header_nav';
-import { AppRootProvider } from './view/app_root_provider';
-import { Setup } from './view/setup';
+import { AppRoot } from './view/app_root';
 
 /**
  * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle.
@@ -37,41 +28,3 @@ export function renderApp(
     ReactDOM.unmountComponentAtNode(element);
   };
 }
-
-interface RouterProps {
-  history: ScopedHistory;
-  store: Store;
-  coreStart: CoreStart;
-  depsStart: EndpointPluginStartDependencies;
-}
-
-const AppRoot: React.FunctionComponent<RouterProps> = React.memo(
-  ({ history, store, coreStart, depsStart }) => {
-    return (
-      <AppRootProvider store={store} history={history} coreStart={coreStart} depsStart={depsStart}>
-        <Setup ingestManager={depsStart.ingestManager} notifications={coreStart.notifications} />
-        <HeaderNavigation />
-        <Switch>
-          <Route
-            exact
-            path="/"
-            render={() => (
-              <h1 data-test-subj="welcomeTitle">
-                <FormattedMessage id="xpack.endpoint.welcomeTitle" defaultMessage="Hello World" />
-              </h1>
-            )}
-          />
-          <Route path="/hosts" component={HostList} />
-          <Route path="/alerts" component={AlertIndex} />
-          <Route path="/policy" exact component={PolicyList} />
-          <Route path="/policy/:id" exact component={PolicyDetails} />
-          <Route
-            render={() => (
-              <FormattedMessage id="xpack.endpoint.notFound" defaultMessage="Page Not Found" />
-            )}
-          />
-        </Switch>
-      </AppRootProvider>
-    );
-  }
-);
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/index.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/index.ts
index f63910a1c305e..5545218d9abd6 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/index.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/index.ts
@@ -6,4 +6,3 @@
 
 export { alertListReducer } from './reducer';
 export { AlertAction } from './action';
-export * from '../../types';
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts
index 18248e272aada..a00ce255cbac4 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts
@@ -4,15 +4,19 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { MiddlewareFactory, PolicyData, PolicyDetailsState } from '../../types';
+import {
+  MiddlewareFactory,
+  PolicyData,
+  PolicyDetailsState,
+  UpdateDatasourceResponse,
+} from '../../types';
 import { policyIdFromParams, isOnPolicyDetailsPage, policyDetails } from './selectors';
+import { generatePolicy } from '../../models/policy';
 import {
   sendGetDatasource,
   sendGetFleetAgentStatusForConfig,
   sendPutDatasource,
-  UpdateDatasourceResponse,
-} from '../../services/ingest';
-import { generatePolicy } from '../../models/policy';
+} from '../policy_list/services/ingest';
 
 export const policyDetailsMiddlewareFactory: MiddlewareFactory<PolicyDetailsState> = coreStart => {
   const http = coreStart.http;
@@ -35,7 +39,6 @@ export const policyDetailsMiddlewareFactory: MiddlewareFactory<PolicyDetailsStat
         return;
       }
 
-      // FIXME: remove this code once the Default Policy is available in the endpoint package - see: https://github.com/elastic/endpoint-app-team/issues/295
       // Until we get the Default configuration into the Endpoint package so that the datasource has
       // the expected data structure, we will add it here manually.
       if (!policyItem.inputs.length) {
@@ -62,7 +65,6 @@ export const policyDetailsMiddlewareFactory: MiddlewareFactory<PolicyDetailsStat
 
       // Agent summary is secondary data, so its ok for it to come after the details
       // page is populated with the main content
-      // FIXME: need to only do this IF fleet is enabled - see: https://github.com/elastic/endpoint-app-team/issues/296
       if (policyItem.config_id) {
         const { results } = await sendGetFleetAgentStatusForConfig(http, policyItem.config_id);
         dispatch({
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts
index ebfee5dbe6a7e..adc176740fb4b 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts
@@ -4,8 +4,8 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { MiddlewareFactory, PolicyListState } from '../../types';
-import { GetDatasourcesResponse, sendGetEndpointSpecificDatasources } from '../../services/ingest';
+import { MiddlewareFactory, PolicyListState, GetDatasourcesResponse } from '../../types';
+import { sendGetEndpointSpecificDatasources } from './services/ingest';
 
 export const policyListMiddlewareFactory: MiddlewareFactory<PolicyListState> = coreStart => {
   const http = coreStart.http;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.test.ts
similarity index 95%
rename from x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts
rename to x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.test.ts
index a2c1dfbe09a48..c2865d36c95f2 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.test.ts
@@ -4,8 +4,8 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { httpServiceMock } from '../../../../../../../src/core/public/mocks';
 import { sendGetDatasource, sendGetEndpointSpecificDatasources } from './ingest';
+import { httpServiceMock } from '../../../../../../../../../src/core/public/mocks';
 
 describe('ingest service', () => {
   let http: ReturnType<typeof httpServiceMock.createStartContract>;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts
similarity index 77%
rename from x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts
rename to x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts
index 583ebc55d896b..16c885f26f0a4 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts
@@ -6,37 +6,21 @@
 
 import { HttpFetchOptions, HttpStart } from 'kibana/public';
 import {
-  CreateDatasourceResponse,
-  GetAgentStatusResponse,
   GetDatasourcesRequest,
-} from '../../../../../ingest_manager/common/types/rest_spec';
-import { NewPolicyData, PolicyData } from '../types';
+  GetAgentStatusResponse,
+} from '../../../../../../../ingest_manager/common';
+import {
+  NewPolicyData,
+  GetDatasourcesResponse,
+  GetDatasourceResponse,
+  UpdateDatasourceResponse,
+} from '../../../types';
 
 const INGEST_API_ROOT = `/api/ingest_manager`;
 const INGEST_API_DATASOURCES = `${INGEST_API_ROOT}/datasources`;
 const INGEST_API_FLEET = `${INGEST_API_ROOT}/fleet`;
 const INGEST_API_FLEET_AGENT_STATUS = `${INGEST_API_FLEET}/agent-status`;
 
-// FIXME: Import from ingest after - https://github.com/elastic/kibana/issues/60677
-export interface GetDatasourcesResponse {
-  items: PolicyData[];
-  total: number;
-  page: number;
-  perPage: number;
-  success: boolean;
-}
-
-// FIXME: Import from Ingest after - https://github.com/elastic/kibana/issues/60677
-export interface GetDatasourceResponse {
-  item: PolicyData;
-  success: boolean;
-}
-
-// FIXME: Import from Ingest after - https://github.com/elastic/kibana/issues/60677
-export type UpdateDatasourceResponse = CreateDatasourceResponse & {
-  item: PolicyData;
-};
-
 /**
  * Retrieves a list of endpoint specific datasources (those created with a `package.name` of
  * `endpoint`) from Ingest
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts
index c7e9970e58c30..f22272bc68233 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts
@@ -4,8 +4,8 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-import { PageId, Immutable } from '../../../../../common/types';
-import { EndpointAppLocation } from '../alerts';
+import { Immutable } from '../../../../../common/types';
+import { EndpointAppLocation, PageId } from '../../types';
 
 interface UserNavigatedToPage {
   readonly type: 'userNavigatedToPage';
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts
index dda50847169e7..f9ad8f6708f6b 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts
@@ -18,7 +18,10 @@ import { EndpointPluginStartDependencies } from '../../plugin';
 import { AppAction } from './store/action';
 import { CoreStart } from '../../../../../../src/core/public';
 import { Datasource, NewDatasource } from '../../../../ingest_manager/common/types/models';
-import { GetAgentStatusResponse } from '../../../../ingest_manager/common/types/rest_spec';
+import {
+  GetAgentStatusResponse,
+  CreateDatasourceResponse,
+} from '../../../../ingest_manager/common/types/rest_spec';
 
 export { AppAction };
 export type MiddlewareFactory<S = GlobalState> = (
@@ -317,3 +320,25 @@ export interface AlertingIndexUIQueryParams {
   date_range?: string;
   filters?: string;
 }
+
+export interface GetDatasourcesResponse {
+  items: PolicyData[];
+  total: number;
+  page: number;
+  perPage: number;
+  success: boolean;
+}
+
+export interface GetDatasourceResponse {
+  item: PolicyData;
+  success: boolean;
+}
+
+export type UpdateDatasourceResponse = CreateDatasourceResponse & {
+  item: PolicyData;
+};
+
+/**
+ * The PageId type is used for the payload when firing userNavigatedToPage actions
+ */
+export type PageId = 'alertsPage' | 'managementPage' | 'policyListPage';
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/app_root.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/app_root.tsx
new file mode 100644
index 0000000000000..f9634c63deefb
--- /dev/null
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/app_root.tsx
@@ -0,0 +1,59 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import * as React from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { Route, Switch } from 'react-router-dom';
+import { Store } from 'redux';
+import { AlertIndex } from './alerts';
+import { HostList } from './hosts';
+import { PolicyList } from './policy';
+import { PolicyDetails } from './policy';
+import { HeaderNavigation } from './components/header_navigation';
+import { AppRootProvider } from './app_root_provider';
+import { Setup } from './setup';
+import { EndpointPluginStartDependencies } from '../../../plugin';
+import { ScopedHistory, CoreStart } from '../../../../../../../src/core/public';
+
+interface RouterProps {
+  history: ScopedHistory;
+  store: Store;
+  coreStart: CoreStart;
+  depsStart: EndpointPluginStartDependencies;
+}
+
+/**
+ * The root of the Endpoint application react view.
+ */
+export const AppRoot: React.FunctionComponent<RouterProps> = React.memo(
+  ({ history, store, coreStart, depsStart }) => {
+    return (
+      <AppRootProvider store={store} history={history} coreStart={coreStart} depsStart={depsStart}>
+        <Setup ingestManager={depsStart.ingestManager} notifications={coreStart.notifications} />
+        <HeaderNavigation />
+        <Switch>
+          <Route
+            exact
+            path="/"
+            render={() => (
+              <h1 data-test-subj="welcomeTitle">
+                <FormattedMessage id="xpack.endpoint.welcomeTitle" defaultMessage="Hello World" />
+              </h1>
+            )}
+          />
+          <Route path="/hosts" component={HostList} />
+          <Route path="/alerts" component={AlertIndex} />
+          <Route path="/policy" exact component={PolicyList} />
+          <Route path="/policy/:id" exact component={PolicyDetails} />
+          <Route
+            render={() => (
+              <FormattedMessage id="xpack.endpoint.notFound" defaultMessage="Page Not Found" />
+            )}
+          />
+        </Switch>
+      </AppRootProvider>
+    );
+  }
+);
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/__snapshots__/link_to_app.test.tsx.snap b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/__snapshots__/link_to_app.test.tsx.snap
similarity index 100%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/__snapshots__/link_to_app.test.tsx.snap
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/__snapshots__/link_to_app.test.tsx.snap
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/__snapshots__/page_view.test.tsx.snap b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/__snapshots__/page_view.test.tsx.snap
similarity index 100%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/__snapshots__/page_view.test.tsx.snap
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/__snapshots__/page_view.test.tsx.snap
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/header_nav.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/header_navigation.tsx
similarity index 90%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/header_nav.tsx
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/header_navigation.tsx
index 3fb06d6b4a56e..6c294d9c86548 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/components/header_nav.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/header_navigation.tsx
@@ -8,15 +8,16 @@ import React, { MouseEvent, useMemo } from 'react';
 import { i18n } from '@kbn/i18n';
 import { EuiTabs, EuiTab } from '@elastic/eui';
 import { useHistory, useLocation } from 'react-router-dom';
-import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
+import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
+import { Immutable } from '../../../../../common/types';
 
-export interface NavTabs {
+interface NavTabs {
   name: string;
   id: string;
   href: string;
 }
 
-export const navTabs: NavTabs[] = [
+const navTabs: Immutable<NavTabs[]> = [
   {
     id: 'home',
     name: i18n.translate('xpack.endpoint.headerNav.home', {
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/link_to_app.test.tsx
similarity index 86%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.test.tsx
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/link_to_app.test.tsx
index 902c215434aac..d0a8f9690dafb 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.test.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/link_to_app.test.tsx
@@ -7,9 +7,14 @@
 import React from 'react';
 import { mount } from 'enzyme';
 import { LinkToApp } from './link_to_app';
-import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public';
-import { coreMock } from '../../../../../../../src/core/public/mocks';
 import { CoreStart } from 'kibana/public';
+import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public';
+import { coreMock } from '../../../../../../../../src/core/public/mocks';
+
+type LinkToAppOnClickMock<Return = void> = jest.Mock<
+  Return,
+  [React.MouseEvent<HTMLAnchorElement, MouseEvent>]
+>;
 
 describe('LinkToApp component', () => {
   let fakeCoreStart: jest.Mocked<CoreStart>;
@@ -38,7 +43,8 @@ describe('LinkToApp component', () => {
     ).toMatchSnapshot();
   });
   it('should support onClick prop', () => {
-    const spyOnClickHandler = jest.fn();
+    // Take `_event` (even though it is not used) so that `jest.fn` will have a type that expects to be called with an event
+    const spyOnClickHandler: LinkToAppOnClickMock = jest.fn(_event => {});
     const renderResult = render(
       <LinkToApp appId="ingestManager" href="/app/ingest" onClick={spyOnClickHandler}>
         link
@@ -91,7 +97,8 @@ describe('LinkToApp component', () => {
     });
   });
   it('should still preventDefault if onClick callback throws', () => {
-    const spyOnClickHandler = jest.fn(ev => {
+    // Take `_event` (even though it is not used) so that `jest.fn` will have a type that expects to be called with an event
+    const spyOnClickHandler: LinkToAppOnClickMock<never> = jest.fn(_event => {
       throw new Error('test');
     });
     const renderResult = render(
@@ -104,7 +111,7 @@ describe('LinkToApp component', () => {
     expect(clickEventArg.isDefaultPrevented()).toBe(true);
   });
   it('should not navigate if onClick callback prevents defalut', () => {
-    const spyOnClickHandler = jest.fn(ev => {
+    const spyOnClickHandler: LinkToAppOnClickMock = jest.fn(ev => {
       ev.preventDefault();
     });
     const renderResult = render(
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/link_to_app.tsx
similarity index 96%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/link_to_app.tsx
index 858dac864b58a..6a3cf5e78f4bf 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/components/link_to_app.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/link_to_app.tsx
@@ -9,7 +9,7 @@ import { EuiLink } from '@elastic/eui';
 import { EuiLinkProps } from '@elastic/eui';
 import { useNavigateToAppEventHandler } from '../hooks/use_navigate_to_app_event_handler';
 
-export type LinkToAppProps = EuiLinkProps & {
+type LinkToAppProps = EuiLinkProps & {
   /** the app id - normally the value of the `id` in that plugin's `kibana.json`  */
   appId: string;
   /** Any app specific path (route) */
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/page_view.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/page_view.test.tsx
similarity index 96%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/page_view.test.tsx
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/page_view.test.tsx
index 0d4d26737d355..4007477a088fa 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/components/page_view.test.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/page_view.test.tsx
@@ -7,7 +7,7 @@
 import React from 'react';
 import { mount } from 'enzyme';
 import { PageView } from './page_view';
-import { EuiThemeProvider } from '../../../../../../legacy/common/eui_styled_components';
+import { EuiThemeProvider } from '../../../../../../../legacy/common/eui_styled_components';
 
 describe('PageView component', () => {
   const render = (ui: Parameters<typeof mount>[0]) =>
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/page_view.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/components/page_view.tsx
similarity index 100%
rename from x-pack/plugins/endpoint/public/applications/endpoint/components/page_view.tsx
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/components/page_view.tsx
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/hooks/use_navigate_to_app_event_handler.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/hooks/use_navigate_to_app_event_handler.ts
similarity index 96%
rename from x-pack/plugins/endpoint/public/applications/endpoint/hooks/use_navigate_to_app_event_handler.ts
rename to x-pack/plugins/endpoint/public/applications/endpoint/view/hooks/use_navigate_to_app_event_handler.ts
index 5fbfa5e0e58a8..ec9a8691c481e 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/hooks/use_navigate_to_app_event_handler.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hooks/use_navigate_to_app_event_handler.ts
@@ -6,7 +6,7 @@
 
 import { MouseEventHandler, useCallback } from 'react';
 import { ApplicationStart } from 'kibana/public';
-import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
+import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
 
 type NavigateToAppHandlerProps = Parameters<ApplicationStart['navigateToApp']>;
 type EventHandlerCallback = MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx
index 90829f7ad4cbe..f51349b24933a 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details.tsx
@@ -28,7 +28,7 @@ import { useHostListSelector } from './hooks';
 import { urlFromQueryParams } from './url_from_query_params';
 import { FormattedDateAndTime } from '../formatted_date_time';
 import { uiQueryParams, detailsData, detailsError } from './../../store/hosts/selectors';
-import { LinkToApp } from '../../components/link_to_app';
+import { LinkToApp } from '../components/link_to_app';
 
 const HostIds = styled(EuiListGroupItem)`
   margin-top: 0;
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx
index c3ff41268e3db..d2d0ad40b025f 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx
@@ -151,7 +151,6 @@ describe('when on the hosts page', () => {
       });
 
       it('should navigate to logs without full page refresh', async () => {
-        // FIXME: this is not working :(
         expect(coreStart.application.navigateToApp.mock.calls).toHaveLength(1);
       });
     });
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx
index 1e723e32615eb..267077da6598c 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_details.tsx
@@ -29,7 +29,7 @@ import {
   isLoading,
   apiError,
 } from '../../store/policy_details/selectors';
-import { PageView, PageViewHeaderTitle } from '../../components/page_view';
+import { PageView, PageViewHeaderTitle } from '../components/page_view';
 import { AppAction } from '../../types';
 import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
 import { AgentsSummary } from './agents_summary';
@@ -82,7 +82,7 @@ export const PolicyDetails = React.memo(() => {
     }
   }, [notifications.toasts, policyItem, policyName, policyUpdateStatus]);
 
-  const handleBackToListOnClick = useCallback(
+  const handleBackToListOnClick: React.MouseEventHandler = useCallback(
     ev => {
       ev.preventDefault();
       history.push(`/policy`);
@@ -161,7 +161,6 @@ export const PolicyDetails = React.memo(() => {
           fill={true}
           iconType="save"
           data-test-subj="policyDetailsSaveButton"
-          // FIXME: need to disable if User has no write permissions to ingest - see: https://github.com/elastic/endpoint-app-team/issues/296
           onClick={handleSaveOnClick}
           isLoading={isPolicyLoading}
         >
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx
index 5ee1539ce9788..06ba74aa46732 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx
@@ -23,8 +23,8 @@ import { usePolicyListSelector } from './policy_hooks';
 import { PolicyListAction } from '../../store/policy_list';
 import { PolicyData } from '../../types';
 import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
-import { PageView } from '../../components/page_view';
-import { LinkToApp } from '../../components/link_to_app';
+import { PageView } from '../components/page_view';
+import { LinkToApp } from '../components/link_to_app';
 
 interface TableChangeCallbackArguments {
   page: { index: number; size: number };
diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts
index 49c39064c8d9a..85ed8a39fb386 100644
--- a/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts
+++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts
@@ -6,8 +6,8 @@
 
 import { useEffect } from 'react';
 import { useDispatch } from 'react-redux';
-import { PageId } from '../../../../common/types';
 import { RoutingAction } from '../store/routing';
+import { PageId } from '../types';
 
 /**
  * Dispatches a 'userNavigatedToPage' action with the given 'pageId' as the action payload.