From ac29d0fc4811ce850353b1f3ec766f4b4778af0b Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Fri, 20 Sep 2024 17:17:20 +0200 Subject: [PATCH] Attempt to get rid of SavedObjectClass (#192265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Another step towards getting rid of the savedobjects plugin which was scheduled for removal since 2019 😓 https://github.com/elastic/kibana/issues/46435 ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../saved_objects_tagging.stub.ts | 1 - .../saved_objects_tagging_service.ts | 2 - .../services/saved_objects_tagging/types.ts | 1 - src/plugins/saved_objects/kibana.jsonc | 3 - src/plugins/saved_objects/public/index.ts | 6 - src/plugins/saved_objects/public/mocks.ts | 19 +- src/plugins/saved_objects/public/plugin.ts | 44 +- .../public/saved_object/decorators/index.ts | 12 - .../saved_object/decorators/registry.mock.ts | 25 - .../saved_object/decorators/registry.test.ts | 126 --- .../saved_object/decorators/registry.ts | 50 - .../public/saved_object/decorators/types.ts | 34 - .../helpers/build_saved_object.ts | 135 --- .../public/saved_object/index.ts | 7 - .../public/saved_object/saved_object.test.ts | 888 ------------------ .../public/saved_object/saved_object.ts | 51 - src/plugins/saved_objects/tsconfig.json | 1 - .../public/api.mock.ts | 2 - .../saved_objects_tagging_oss/public/api.ts | 14 - .../decorator/decorate_config.test.mocks.ts | 18 - .../public/decorator/decorate_config.test.ts | 133 --- .../public/decorator/decorate_config.ts | 36 - .../public/decorator/decorate_object.test.ts | 41 - .../public/decorator/decorate_object.ts | 22 - .../decorator/extract_tag_references.test.ts | 101 -- .../decorator/extract_tag_references.ts | 34 - .../public/decorator/factory.ts | 25 - .../public/decorator/index.ts | 20 - .../decorator/inject_tag_references.test.ts | 60 -- .../public/decorator/inject_tag_references.ts | 25 - .../public/decorator/types.ts | 25 - .../saved_objects_tagging_oss/public/index.ts | 3 - .../public/plugin.test.ts | 25 +- .../public/plugin.ts | 15 +- .../saved_objects_tagging_oss/tsconfig.json | 1 - src/plugins/visualizations/public/mocks.ts | 2 - src/plugins/visualizations/public/plugin.ts | 2 - .../public/ui_api/has_tag_decoration.ts | 17 - .../public/ui_api/index.ts | 2 - .../public/app/__mocks__/app_dependencies.tsx | 2 - .../transform/public/app/app_dependencies.tsx | 2 - .../public/app/mount_management_section.ts | 1 - x-pack/plugins/transform/public/plugin.ts | 2 - x-pack/plugins/transform/tsconfig.json | 1 - 44 files changed, 10 insertions(+), 2026 deletions(-) delete mode 100644 src/plugins/saved_objects/public/saved_object/decorators/index.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/decorators/registry.mock.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/decorators/registry.test.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/decorators/registry.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/decorators/types.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/saved_object.test.ts delete mode 100644 src/plugins/saved_objects/public/saved_object/saved_object.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.mocks.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.test.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.test.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/factory.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/index.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.test.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.ts delete mode 100644 src/plugins/saved_objects_tagging_oss/public/decorator/types.ts delete mode 100644 x-pack/plugins/saved_objects_tagging/public/ui_api/has_tag_decoration.ts diff --git a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts b/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts index 5c04a7c5c4890..ed8e4e5486dad 100644 --- a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts +++ b/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts @@ -21,7 +21,6 @@ export const savedObjectsTaggingServiceFactory: SavedObjectsTaggingServiceFactor // I'm not defining components so that I don't have to update the snapshot of `save_modal.test` // However, if it's ever necessary, it can be done via: `components: pluginMock.components`, - hasTagDecoration: pluginMock.hasTagDecoration, parseSearchQuery: pluginMock.parseSearchQuery, getSearchBarFilter: pluginMock.getSearchBarFilter, getTagIdsFromReferences: pluginMock.getTagIdsFromReferences, diff --git a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts b/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts index 2eb49f79169ed..4440ee069d2bc 100644 --- a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts +++ b/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts @@ -29,7 +29,6 @@ export const savedObjectsTaggingServiceFactory: SavedObjectsTaggingServiceFactor ui: { components, parseSearchQuery, - hasTagDecoration, getSearchBarFilter, updateTagsReferences, getTagIdsFromReferences, @@ -42,7 +41,6 @@ export const savedObjectsTaggingServiceFactory: SavedObjectsTaggingServiceFactor hasApi: true, api: taggingApi, components, - hasTagDecoration, parseSearchQuery, getSearchBarFilter, updateTagsReferences, diff --git a/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts b/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts index 340849a3b9406..f08aa7c6c28f2 100644 --- a/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts +++ b/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts @@ -13,7 +13,6 @@ export interface DashboardSavedObjectsTaggingService { hasApi: boolean; // remove this once the entire service is optional api?: SavedObjectsTaggingApi; components?: SavedObjectsTaggingApi['ui']['components']; - hasTagDecoration?: SavedObjectsTaggingApi['ui']['hasTagDecoration']; parseSearchQuery?: SavedObjectsTaggingApi['ui']['parseSearchQuery']; getSearchBarFilter?: SavedObjectsTaggingApi['ui']['getSearchBarFilter']; updateTagsReferences?: SavedObjectsTaggingApi['ui']['updateTagsReferences']; diff --git a/src/plugins/saved_objects/kibana.jsonc b/src/plugins/saved_objects/kibana.jsonc index aa1c9aae31194..1f063a7cdfa59 100644 --- a/src/plugins/saved_objects/kibana.jsonc +++ b/src/plugins/saved_objects/kibana.jsonc @@ -9,9 +9,6 @@ "requiredPlugins": [ "data", "dataViews" - ], - "requiredBundles": [ - "kibanaUtils" ] } } diff --git a/src/plugins/saved_objects/public/index.ts b/src/plugins/saved_objects/public/index.ts index 4ce1d679c743f..6d7a013cf59ca 100644 --- a/src/plugins/saved_objects/public/index.ts +++ b/src/plugins/saved_objects/public/index.ts @@ -11,13 +11,7 @@ import { SavedObjectsPublicPlugin } from './plugin'; export type { OnSaveProps, OriginSaveModalProps, SaveModalState, SaveResult } from './save_modal'; export { SavedObjectSaveModal, SavedObjectSaveModalOrigin, showSaveModal } from './save_modal'; -export type { - SavedObjectDecorator, - SavedObjectDecoratorFactory, - SavedObjectDecoratorConfig, -} from './saved_object'; export { checkForDuplicateTitle, saveWithConfirmation, isErrorNonFatal } from './saved_object'; export type { SavedObjectSaveOpts, SavedObject, SavedObjectConfig } from './types'; -export type { SavedObjectsStart, SavedObjectSetup } from './plugin'; export const plugin = () => new SavedObjectsPublicPlugin(); diff --git a/src/plugins/saved_objects/public/mocks.ts b/src/plugins/saved_objects/public/mocks.ts index 124f9bcd2d659..5d15efcb0b22f 100644 --- a/src/plugins/saved_objects/public/mocks.ts +++ b/src/plugins/saved_objects/public/mocks.ts @@ -7,21 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { SavedObjectsStart, SavedObjectSetup } from './plugin'; - -const createStartContract = (): SavedObjectsStart => { - return { - SavedObjectClass: jest.fn(), - }; -}; - -const createSetupContract = (): jest.Mocked => { - return { - registerDecorator: jest.fn(), - }; -}; - -export const savedObjectsPluginMock = { - createStartContract, - createSetupContract, -}; +export const savedObjectsPluginMock = {}; diff --git a/src/plugins/saved_objects/public/plugin.ts b/src/plugins/saved_objects/public/plugin.ts index cbf3a5e69cf7f..fd67e783fab75 100644 --- a/src/plugins/saved_objects/public/plugin.ts +++ b/src/plugins/saved_objects/public/plugin.ts @@ -12,55 +12,19 @@ import { CoreStart, Plugin } from '@kbn/core/public'; import './index.scss'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { - createSavedObjectClass, - SavedObjectDecoratorRegistry, - SavedObjectDecoratorConfig, -} from './saved_object'; -import { SavedObject } from './types'; import { setStartServices } from './kibana_services'; -export interface SavedObjectSetup { - registerDecorator: (config: SavedObjectDecoratorConfig) => void; -} - -export interface SavedObjectsStart { - /** - * @deprecated - * @removeBy 8.8.0 - */ - SavedObjectClass: new (raw: Record) => SavedObject; -} - export interface SavedObjectsStartDeps { data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; } -export class SavedObjectsPublicPlugin - implements Plugin -{ - private decoratorRegistry = new SavedObjectDecoratorRegistry(); - - public setup(): SavedObjectSetup { - return { - registerDecorator: (config) => this.decoratorRegistry.register(config), - }; +export class SavedObjectsPublicPlugin implements Plugin<{}, {}, object, SavedObjectsStartDeps> { + public setup() { + return {}; } public start(core: CoreStart, { data, dataViews }: SavedObjectsStartDeps) { setStartServices(core); - return { - SavedObjectClass: createSavedObjectClass( - { - dataViews, - savedObjectsClient: core.savedObjects.client, - search: data.search, - chrome: core.chrome, - overlays: core.overlays, - }, - core, - this.decoratorRegistry - ), - }; + return {}; } } diff --git a/src/plugins/saved_objects/public/saved_object/decorators/index.ts b/src/plugins/saved_objects/public/saved_object/decorators/index.ts deleted file mode 100644 index 62f4f27bd2590..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/decorators/index.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export type { ISavedObjectDecoratorRegistry, SavedObjectDecoratorConfig } from './registry'; -export { SavedObjectDecoratorRegistry } from './registry'; -export type { SavedObjectDecorator, SavedObjectDecoratorFactory } from './types'; diff --git a/src/plugins/saved_objects/public/saved_object/decorators/registry.mock.ts b/src/plugins/saved_objects/public/saved_object/decorators/registry.mock.ts deleted file mode 100644 index ad292b65e4e51..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/decorators/registry.mock.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ISavedObjectDecoratorRegistry } from './registry'; - -const createRegistryMock = () => { - const mock: jest.Mocked = { - register: jest.fn(), - getOrderedDecorators: jest.fn(), - }; - - mock.getOrderedDecorators.mockReturnValue([]); - - return mock; -}; - -export const savedObjectsDecoratorRegistryMock = { - create: createRegistryMock, -}; diff --git a/src/plugins/saved_objects/public/saved_object/decorators/registry.test.ts b/src/plugins/saved_objects/public/saved_object/decorators/registry.test.ts deleted file mode 100644 index 590e2717c48ff..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/decorators/registry.test.ts +++ /dev/null @@ -1,126 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectDecoratorRegistry } from './registry'; - -const mockDecorator = (id: string = 'foo') => { - return { - getId: () => id, - decorateConfig: () => undefined, - decorateObject: () => undefined, - }; -}; - -describe('SavedObjectDecoratorRegistry', () => { - let registry: SavedObjectDecoratorRegistry; - - beforeEach(() => { - registry = new SavedObjectDecoratorRegistry(); - }); - - describe('register', () => { - it('allow to register a decorator', () => { - expect(() => { - registry.register({ - id: 'foo', - priority: 9000, - factory: () => mockDecorator(), - }); - }).not.toThrow(); - }); - - it('throws when trying to register the same id twice', () => { - registry.register({ - id: 'foo', - priority: 9000, - factory: () => mockDecorator(), - }); - - expect(() => { - registry.register({ - id: 'foo', - priority: 42, - factory: () => mockDecorator(), - }); - }).toThrowErrorMatchingInlineSnapshot(`"A decorator is already registered for id foo"`); - }); - - it('throws when trying to register multiple decorators with the same priority', () => { - registry.register({ - id: 'foo', - priority: 100, - factory: () => mockDecorator(), - }); - - expect(() => { - registry.register({ - id: 'bar', - priority: 100, - factory: () => mockDecorator(), - }); - }).toThrowErrorMatchingInlineSnapshot(`"A decorator is already registered for priority 100"`); - }); - }); - - describe('getOrderedDecorators', () => { - it('returns the decorators in correct order', () => { - registry.register({ - id: 'A', - priority: 1000, - factory: () => mockDecorator('A'), - }); - registry.register({ - id: 'B', - priority: 100, - factory: () => mockDecorator('B'), - }); - registry.register({ - id: 'C', - priority: 2000, - factory: () => mockDecorator('C'), - }); - - const decorators = registry.getOrderedDecorators({} as any); - expect(decorators.map((d) => d.getId())).toEqual(['B', 'A', 'C']); - }); - - it('invoke the decorators factory with the provided services', () => { - const services = Symbol('services'); - - const decorator = { - id: 'foo', - priority: 9000, - factory: jest.fn(), - }; - registry.register(decorator); - registry.getOrderedDecorators(services as any); - - expect(decorator.factory).toHaveBeenCalledTimes(1); - expect(decorator.factory).toHaveBeenCalledWith(services); - }); - - it('invoke the factory each time the method is called', () => { - const services = Symbol('services'); - - const decorator = { - id: 'foo', - priority: 9000, - factory: jest.fn(), - }; - registry.register(decorator); - registry.getOrderedDecorators(services as any); - - expect(decorator.factory).toHaveBeenCalledTimes(1); - - registry.getOrderedDecorators(services as any); - - expect(decorator.factory).toHaveBeenCalledTimes(2); - }); - }); -}); diff --git a/src/plugins/saved_objects/public/saved_object/decorators/registry.ts b/src/plugins/saved_objects/public/saved_object/decorators/registry.ts deleted file mode 100644 index 816ba2a84c1ae..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/decorators/registry.ts +++ /dev/null @@ -1,50 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PublicMethodsOf } from '@kbn/utility-types'; -import { SavedObjectDecoratorFactory } from './types'; -import { SavedObjectKibanaServices, SavedObject } from '../../types'; - -export interface SavedObjectDecoratorConfig { - /** - * The id of the decorator - */ - id: string; - /** - * Highest priority will be called **last** - * (the decoration will be at the highest level) - */ - priority: number; - /** - * The factory to use to create the decorator - */ - factory: SavedObjectDecoratorFactory; -} - -export type ISavedObjectDecoratorRegistry = PublicMethodsOf; - -export class SavedObjectDecoratorRegistry { - private readonly registry = new Map>(); - - public register(config: SavedObjectDecoratorConfig) { - if (this.registry.has(config.id)) { - throw new Error(`A decorator is already registered for id ${config.id}`); - } - if ([...this.registry.values()].find(({ priority }) => priority === config.priority)) { - throw new Error(`A decorator is already registered for priority ${config.priority}`); - } - this.registry.set(config.id, config); - } - - public getOrderedDecorators(services: SavedObjectKibanaServices) { - return [...this.registry.values()] - .sort((a, b) => a.priority - b.priority) - .map(({ factory }) => factory(services)); - } -} diff --git a/src/plugins/saved_objects/public/saved_object/decorators/types.ts b/src/plugins/saved_objects/public/saved_object/decorators/types.ts deleted file mode 100644 index 8f992a46a8fb9..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/decorators/types.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObject, SavedObjectKibanaServices, SavedObjectConfig } from '../../types'; - -export interface SavedObjectDecorator { - /** - * Id of the decorator - */ - getId(): string; - - /** - * Decorate the saved object provided config. This can be used to enhance or alter the object's provided - * configuration. - */ - decorateConfig: (config: SavedObjectConfig) => void; - /** - * Decorate the saved object instance. Can be used to add additional methods to it. - * - * @remarks This will be called before the internal constructor of the object, meaning that - * wrapping existing methods is not possible (and is not a desired pattern). - */ - decorateObject: (object: T) => void; -} - -export type SavedObjectDecoratorFactory = ( - services: SavedObjectKibanaServices -) => SavedObjectDecorator; 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 deleted file mode 100644 index 388f84fcd524d..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts +++ /dev/null @@ -1,135 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { once } from 'lodash'; -import { hydrateIndexPattern } from './hydrate_index_pattern'; -import { intializeSavedObject } from './initialize_saved_object'; -import { serializeSavedObject } from './serialize_saved_object'; - -import { - EsResponse, - SavedObject, - SavedObjectConfig, - SavedObjectKibanaServices, - SavedObjectSaveOpts, - StartServices, -} from '../../types'; -import { applyESResp } from './apply_es_resp'; -import { saveSavedObject } from './save_saved_object'; -import { SavedObjectDecorator } from '../decorators'; - -const applyDecorators = ( - object: SavedObject, - config: SavedObjectConfig, - decorators: SavedObjectDecorator[] -) => { - decorators.forEach((decorator) => { - decorator.decorateConfig(config); - decorator.decorateObject(object); - }); -}; - -export function buildSavedObject( - savedObject: SavedObject, - config: SavedObjectConfig, - services: SavedObjectKibanaServices, - startServices: StartServices, - decorators: SavedObjectDecorator[] = [] -) { - applyDecorators(savedObject, config, decorators); - - const { dataViews, savedObjectsClient } = services; - // type name for this object, used as the ES-type - const esType = config.type || ''; - - savedObject.getDisplayName = () => esType; - - // NOTE: this.type (not set in this file, but somewhere else) is the sub type, e.g. 'area' or - // 'data table', while esType is the more generic type - e.g. 'visualization' or 'saved search'. - savedObject.getEsType = () => esType; - - /** - * Flips to true during a save operation, and back to false once the save operation - * completes. - * @type {boolean} - */ - savedObject.isSaving = false; - savedObject.defaults = config.defaults || {}; - // optional search source which this object configures - savedObject.searchSource = config.searchSource - ? services.search.searchSource.createEmpty() - : undefined; - // the id of the document - savedObject.id = config.id || void 0; - // the migration version of the document, should only be set on imports - savedObject.migrationVersion = config.migrationVersion; - // Whether to create a copy when the object is saved. This should eventually go away - // in favor of a better rename/save flow. - savedObject.copyOnSave = false; - - /** - * After creation or fetching from ES, ensure that the searchSources index indexPattern - * is an bonafide IndexPattern object. - * - * @return {Promise} - */ - savedObject.hydrateIndexPattern = (id?: string) => - hydrateIndexPattern(id || '', savedObject, dataViews, config); - /** - * Asynchronously initialize this object - will only run - * once even if called multiple times. - * - * @return {Promise} - * @resolved {SavedObject} - */ - savedObject.init = once(() => intializeSavedObject(savedObject, savedObjectsClient, config)); - - savedObject.applyESResp = (resp: EsResponse) => applyESResp(resp, savedObject, config, services); - - /** - * Serialize this object - * @return {Object} - */ - savedObject._serialize = () => serializeSavedObject(savedObject, config); - - /** - * Returns true if the object's original title has been changed. New objects return false. - * @return {boolean} - */ - savedObject.isTitleChanged = () => - savedObject._source && savedObject._source.title !== savedObject.title; - - savedObject.creationOpts = (opts: Record = {}) => ({ - id: savedObject.id, - migrationVersion: savedObject.migrationVersion, - ...opts, - }); - - savedObject.save = async (opts: SavedObjectSaveOpts) => { - try { - const result = await saveSavedObject(savedObject, config, opts, services, startServices); - return Promise.resolve(result); - } catch (e) { - return Promise.reject(e); - } - }; - - savedObject.destroy = () => {}; - - /** - * Delete this object from Elasticsearch - * @return {promise} - */ - savedObject.delete = () => { - if (!savedObject.id) { - return Promise.reject(new Error('Deleting a saved Object requires type and id')); - } - return savedObjectsClient.delete(esType, savedObject.id); - }; -} diff --git a/src/plugins/saved_objects/public/saved_object/index.ts b/src/plugins/saved_objects/public/saved_object/index.ts index 89cfa263093b1..560178fdf4f36 100644 --- a/src/plugins/saved_objects/public/saved_object/index.ts +++ b/src/plugins/saved_objects/public/saved_object/index.ts @@ -7,13 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { createSavedObjectClass } from './saved_object'; export { checkForDuplicateTitle } from './helpers/check_for_duplicate_title'; export { saveWithConfirmation } from './helpers/save_with_confirmation'; export { isErrorNonFatal } from './helpers/save_saved_object'; -export type { - SavedObjectDecoratorFactory, - SavedObjectDecorator, - SavedObjectDecoratorConfig, -} from './decorators'; -export { SavedObjectDecoratorRegistry } from './decorators'; 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 deleted file mode 100644 index 645ae855b277b..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts +++ /dev/null @@ -1,888 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { createSavedObjectClass } from './saved_object'; -import { - SavedObject, - SavedObjectConfig, - SavedObjectKibanaServices, - SavedObjectSaveOpts, -} from '../types'; -import { SavedObjectDecorator } from './decorators'; - -import { - analyticsServiceMock, - coreMock, - i18nServiceMock, - themeServiceMock, -} from '@kbn/core/public/mocks'; -import { dataPluginMock, createSearchSourceMock } from '@kbn/data-plugin/public/mocks'; -import { createStubIndexPattern } from '@kbn/data-plugin/common/stubs'; -import { SavedObjectAttributes, SimpleSavedObject } from '@kbn/core/public'; -import { DataView } from '@kbn/data-plugin/common'; -import { savedObjectsDecoratorRegistryMock } from './decorators/registry.mock'; - -describe('Saved Object', () => { - const startMock = coreMock.createStart(); - const dataStartMock = dataPluginMock.createStartContract(); - const saveOptionsMock = {} as SavedObjectSaveOpts; - const savedObjectsClientStub = startMock.savedObjects.client; - const startServices = { - analytics: analyticsServiceMock.createAnalyticsServiceStart(), - i18n: i18nServiceMock.createStartContract(), - theme: themeServiceMock.createStartContract(), - }; - let decoratorRegistry: ReturnType; - - let SavedObjectClass: new (config: SavedObjectConfig) => SavedObject; - - /** - * Returns a fake doc response with the given index and id, of type dashboard - * that can be used to stub es calls. - * @param indexPatternId - * @param additionalOptions - object that will be assigned to the mocked doc response. - * @returns {{attributes: {}, type: string, id: *, _version: string}} - */ - function getMockedDocResponse(indexPatternId: string, additionalOptions = {}) { - return { - type: 'dashboard', - id: indexPatternId, - _version: 'foo', - attributes: {}, - ...additionalOptions, - } as SimpleSavedObject; - } - - /** - * Stubs some of the es retrieval calls so it returns the given response. - * @param {Object} mockDocResponse - */ - function stubESResponse(mockDocResponse: SimpleSavedObject) { - // Stub out search for duplicate title: - savedObjectsClientStub.get = jest.fn().mockReturnValue(Promise.resolve(mockDocResponse)); - savedObjectsClientStub.update = jest.fn().mockReturnValue(Promise.resolve(mockDocResponse)); - - savedObjectsClientStub.find = jest - .fn() - .mockReturnValue(Promise.resolve({ savedObjects: [], total: 0 })); - - savedObjectsClientStub.bulkGet = jest - .fn() - .mockReturnValue(Promise.resolve({ savedObjects: [mockDocResponse] })); - } - - function stubSavedObjectsClientCreate( - resp: SimpleSavedObject | string, - resolve = true - ) { - savedObjectsClientStub.create = jest - .fn() - .mockReturnValue(resolve ? Promise.resolve(resp) : Promise.reject(resp)); - } - - /** - * Creates a new saved object with the given configuration and initializes it. - * Returns the promise that will be completed when the initialization finishes. - * - * @param {Object} config - * @returns {Promise} A promise that resolves with an instance of - * SavedObject - */ - function createInitializedSavedObject(config: SavedObjectConfig = { type: 'dashboard' }) { - const savedObject = new SavedObjectClass(config); - savedObject.title = 'my saved object'; - - return savedObject.init!(); - } - - const initSavedObjectClass = () => { - SavedObjectClass = createSavedObjectClass( - { - savedObjectsClient: savedObjectsClientStub, - indexPatterns: dataStartMock.indexPatterns, - search: { - ...dataStartMock.search, - searchSource: { - ...dataStartMock.search.searchSource, - create: createSearchSourceMock, - createEmpty: createSearchSourceMock, - }, - }, - } as unknown as SavedObjectKibanaServices, - startServices, - decoratorRegistry - ); - }; - - beforeEach(() => { - decoratorRegistry = savedObjectsDecoratorRegistryMock.create(); - initSavedObjectClass(); - }); - - describe('decorators', () => { - it('calls the decorators during construct', () => { - const decorA = { - getId: () => 'A', - decorateConfig: jest.fn(), - decorateObject: jest.fn(), - }; - const decorB = { - getId: () => 'B', - decorateConfig: jest.fn(), - decorateObject: jest.fn(), - }; - - decoratorRegistry.getOrderedDecorators.mockReturnValue([decorA, decorB]); - - initSavedObjectClass(); - createInitializedSavedObject(); - - expect(decorA.decorateConfig).toHaveBeenCalledTimes(1); - expect(decorA.decorateObject).toHaveBeenCalledTimes(1); - }); - - it('calls the decorators in correct order', () => { - const decorA = { - getId: () => 'A', - decorateConfig: jest.fn(), - decorateObject: jest.fn(), - }; - const decorB = { - getId: () => 'B', - decorateConfig: jest.fn(), - decorateObject: jest.fn(), - }; - - decoratorRegistry.getOrderedDecorators.mockReturnValue([decorA, decorB]); - - initSavedObjectClass(); - createInitializedSavedObject(); - - expect(decorA.decorateConfig.mock.invocationCallOrder[0]).toBeLessThan( - decorB.decorateConfig.mock.invocationCallOrder[0] - ); - expect(decorA.decorateObject.mock.invocationCallOrder[0]).toBeLessThan( - decorB.decorateObject.mock.invocationCallOrder[0] - ); - }); - - it('passes the mutated config and object down the decorator chain', () => { - expect.assertions(2); - - const newMappingValue = 'string'; - const newObjectMethod = jest.fn(); - - const decorA: SavedObjectDecorator = { - getId: () => 'A', - decorateConfig: (config) => { - config.mapping = { - ...config.mapping, - addedFromA: newMappingValue, - }; - }, - decorateObject: (object) => { - (object as any).newMethod = newObjectMethod; - }, - }; - const decorB: SavedObjectDecorator = { - getId: () => 'B', - decorateConfig: (config) => { - expect(config.mapping!.addedFromA).toBe(newMappingValue); - }, - decorateObject: (object) => { - expect((object as any).newMethod).toBe(newObjectMethod); - }, - }; - - decoratorRegistry.getOrderedDecorators.mockReturnValue([decorA, decorB]); - - initSavedObjectClass(); - createInitializedSavedObject(); - }); - }); - - describe('save', () => { - describe('with confirmOverwrite', () => { - it('when false does not request overwrite', () => { - stubESResponse(getMockedDocResponse('myId')); - - return createInitializedSavedObject({ type: 'dashboard', id: 'myId' }).then( - (savedObject) => { - stubSavedObjectsClientCreate({ - id: 'myId', - } as SimpleSavedObject); - - return savedObject.save({ confirmOverwrite: false }).then(() => { - expect(startMock.overlays.openModal).not.toHaveBeenCalled(); - }); - } - ); - }); - }); - - describe('with copyOnSave', () => { - it('as true creates a copy on save success', () => { - stubESResponse(getMockedDocResponse('myId')); - - return createInitializedSavedObject({ type: 'dashboard', id: 'myId' }).then( - (savedObject) => { - stubSavedObjectsClientCreate({ - type: 'dashboard', - id: 'newUniqueId', - } as SimpleSavedObject); - savedObject.copyOnSave = true; - - return savedObject.save(saveOptionsMock).then((id) => { - expect(id).toBe('newUniqueId'); - }); - } - ); - }); - - it('as true does not create a copy when save fails', () => { - const originalId = 'id1'; - stubESResponse(getMockedDocResponse(originalId)); - - return createInitializedSavedObject({ type: 'dashboard', id: originalId }).then( - (savedObject) => { - stubSavedObjectsClientCreate('simulated error', false); - savedObject.copyOnSave = true; - - return savedObject - .save(saveOptionsMock) - .then(() => { - expect(false).toBe(true); - }) - .catch(() => { - expect(savedObject.id).toBe(originalId); - }); - } - ); - }); - - it('as false does not create a copy', () => { - const myId = 'myId'; - stubESResponse(getMockedDocResponse(myId)); - - return createInitializedSavedObject({ type: 'dashboard', id: myId }).then((savedObject) => { - savedObjectsClientStub.create = jest.fn().mockImplementation(() => { - expect(savedObject.id).toBe(myId); - return Promise.resolve({ id: myId }); - }); - savedObject.copyOnSave = false; - - return savedObject.save(saveOptionsMock).then((id) => { - expect(id).toBe(myId); - }); - }); - }); - }); - - it('returns id from server on success', () => { - return createInitializedSavedObject({ type: 'dashboard' }).then((savedObject) => { - stubESResponse(getMockedDocResponse('myId')); - stubSavedObjectsClientCreate({ - type: 'dashboard', - id: 'myId', - _version: 'foo', - } as SimpleSavedObject); - - return savedObject.save(saveOptionsMock).then((id) => { - expect(id).toBe('myId'); - }); - }); - }); - - describe('updates isSaving variable', () => { - it('on success', () => { - const id = 'id'; - stubESResponse(getMockedDocResponse(id)); - - return createInitializedSavedObject({ type: 'dashboard', id }).then((savedObject) => { - savedObjectsClientStub.create = jest.fn().mockImplementation(() => { - expect(savedObject.isSaving).toBe(true); - return Promise.resolve({ - type: 'dashboard', - id, - _version: 'foo', - }); - }); - - expect(savedObject.isSaving).toBe(false); - return savedObject.save(saveOptionsMock).then(() => { - expect(savedObject.isSaving).toBe(false); - }); - }); - }); - - it('on failure', () => { - stubESResponse(getMockedDocResponse('id')); - return createInitializedSavedObject({ type: 'dashboard' }).then((savedObject) => { - savedObjectsClientStub.create = jest.fn().mockImplementation(() => { - expect(savedObject.isSaving).toBe(true); - return Promise.reject(''); - }); - - expect(savedObject.isSaving).toBe(false); - return savedObject.save(saveOptionsMock).catch(() => { - expect(savedObject.isSaving).toBe(false); - }); - }); - }); - }); - - describe('to extract references', () => { - it('when "extractReferences" function when passed in', async () => { - const id = '123'; - stubESResponse(getMockedDocResponse(id)); - const extractReferences: SavedObjectConfig['extractReferences'] = ({ - attributes, - references, - }) => { - references.push({ - name: 'test', - type: 'index-pattern', - id: 'my-index', - }); - return { attributes, references }; - }; - return createInitializedSavedObject({ type: 'dashboard', extractReferences }).then( - (savedObject) => { - stubSavedObjectsClientCreate({ - id, - _version: 'foo', - type: 'dashboard', - } as SimpleSavedObject); - - return savedObject.save(saveOptionsMock).then(() => { - const { references } = (savedObjectsClientStub.create as jest.Mock).mock.calls[0][2]; - expect(references).toHaveLength(1); - expect(references[0]).toEqual({ - name: 'test', - type: 'index-pattern', - id: 'my-index', - }); - }); - } - ); - }); - - it('when search source references saved object', () => { - const id = '123'; - stubESResponse(getMockedDocResponse(id)); - return createInitializedSavedObject({ type: 'dashboard', searchSource: true }).then( - (savedObject) => { - stubSavedObjectsClientCreate({ - id, - _version: '2', - type: 'dashboard', - } as SimpleSavedObject); - - const indexPattern = createStubIndexPattern({ - spec: { id: 'my-index', title: 'my-index', version: '1' }, - }); - savedObject.searchSource!.setField('index', indexPattern); - return savedObject.save(saveOptionsMock).then(() => { - const args = (savedObjectsClientStub.create as jest.Mock).mock.calls[0]; - expect(args[1]).toEqual({ - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index', - }), - }, - }); - - expect(args[2].references).toHaveLength(1); - expect(args[2].references[0]).toEqual({ - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - id: 'my-index', - }); - }); - } - ); - }); - - it('when index in searchSourceJSON is not found', () => { - const id = '123'; - stubESResponse(getMockedDocResponse(id)); - return createInitializedSavedObject({ type: 'dashboard', searchSource: true }).then( - (savedObject) => { - stubSavedObjectsClientCreate({ - id, - _version: '2', - type: 'dashboard', - } as SimpleSavedObject); - - const indexPattern = createStubIndexPattern({ - spec: { - id: 'non-existant-index', - version: '1', - }, - }); - - savedObject.searchSource!.setField('index', indexPattern); - return savedObject.save(saveOptionsMock).then(() => { - const args = (savedObjectsClientStub.create as jest.Mock).mock.calls[0]; - expect(args[1]).toEqual({ - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index', - }), - }, - }); - expect(args[2].references).toHaveLength(1); - expect(args[2].references[0]).toEqual({ - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - id: 'non-existant-index', - }); - }); - } - ); - }); - - it('when indexes exists in filter of searchSourceJSON', () => { - const id = '123'; - stubESResponse(getMockedDocResponse(id)); - return createInitializedSavedObject({ type: 'dashboard', searchSource: true }).then( - (savedObject) => { - stubSavedObjectsClientCreate({ - id, - _version: '2', - type: 'dashboard', - } as SimpleSavedObject); - - savedObject.searchSource!.setField('filter', [ - { - meta: { - index: 'my-index', - }, - }, - ] as any); - return savedObject.save(saveOptionsMock).then(() => { - const args = (savedObjectsClientStub.create as jest.Mock).mock.calls[0]; - expect(args[1]).toEqual({ - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - filter: [ - { - meta: { - indexRefName: - 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index', - }, - }, - ], - }), - }, - }); - expect(args[2].references).toHaveLength(1); - expect(args[2].references[0]).toEqual({ - name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index', - type: 'index-pattern', - id: 'my-index', - }); - }); - } - ); - }); - }); - }); - - describe('applyESResp', () => { - it('throws error if not found', () => { - return createInitializedSavedObject({ type: 'dashboard' }).then((savedObject) => { - const response = { _source: {} }; - try { - savedObject.applyESResp(response); - expect(true).toBe(false); - } catch (err) { - expect(!!err).toBe(true); - } - }); - }); - - it('preserves original defaults if not overridden', () => { - const id = 'anid'; - const preserveMeValue = 'here to stay!'; - const config = { - defaults: { - preserveMe: preserveMeValue, - }, - type: 'dashboard', - id, - }; - - const mockDocResponse = getMockedDocResponse(id); - stubESResponse(mockDocResponse); - - const savedObject = new SavedObjectClass(config); - return savedObject.init!() - .then(() => { - expect(savedObject._source.preserveMe).toEqual(preserveMeValue); - const response = { found: true, _source: {} }; - return savedObject.applyESResp(response); - }) - .then(() => { - expect(savedObject._source.preserveMe).toEqual(preserveMeValue); - }); - }); - - it('overrides defaults', () => { - const id = 'anid'; - const config = { - defaults: { - flower: 'rose', - }, - type: 'dashboard', - id, - }; - - stubESResponse(getMockedDocResponse(id)); - - const savedObject = new SavedObjectClass(config); - return savedObject.init!() - .then(() => { - expect(savedObject._source.flower).toEqual('rose'); - const response = { - found: true, - _source: { - flower: 'orchid', - }, - }; - return savedObject.applyESResp(response); - }) - .then(() => { - expect(savedObject._source.flower).toEqual('orchid'); - }); - }); - - it('overrides previous _source and default values', () => { - const id = 'anid'; - const config = { - defaults: { - dinosaurs: { - tRex: 'is the scariest', - }, - }, - type: 'dashboard', - id, - }; - - const mockDocResponse = getMockedDocResponse(id, { - attributes: { dinosaurs: { tRex: 'is not so bad' } }, - }); - stubESResponse(mockDocResponse); - - const savedObject = new SavedObjectClass(config); - return savedObject.init!() - .then(() => { - const response = { - found: true, - _source: { dinosaurs: { tRex: 'has big teeth' } }, - }; - - return savedObject.applyESResp(response); - }) - .then(() => { - expect((savedObject._source as any).dinosaurs.tRex).toEqual('has big teeth'); - }); - }); - - it('does not inject references when references array is missing', async () => { - const injectReferences = jest.fn(); - const config = { - type: 'dashboard', - injectReferences, - }; - const savedObject = new SavedObjectClass(config); - return savedObject.init!() - .then(() => { - const response = { - found: true, - _source: { - dinosaurs: { tRex: 'has big teeth' }, - }, - }; - return savedObject.applyESResp(response); - }) - .then(() => { - expect(injectReferences).not.toHaveBeenCalled(); - }); - }); - - it('does not inject references when references array is empty', async () => { - const injectReferences = jest.fn(); - const config = { - type: 'dashboard', - injectReferences, - }; - const savedObject = new SavedObjectClass(config); - return savedObject.init!() - .then(() => { - const response = { - found: true, - _source: { - dinosaurs: { tRex: 'has big teeth' }, - }, - references: [], - }; - return savedObject.applyESResp(response); - }) - .then(() => { - expect(injectReferences).not.toHaveBeenCalled(); - }); - }); - - it('injects references when function is provided and references exist', async () => { - const injectReferences = jest.fn(); - const config = { - type: 'dashboard', - injectReferences, - }; - const savedObject = new SavedObjectClass(config); - return savedObject.init!() - .then(() => { - const response = { - found: true, - _source: { - dinosaurs: { tRex: 'has big teeth' }, - }, - references: [{}], - }; - return savedObject.applyESResp(response); - }) - .then(() => { - expect(injectReferences).toHaveBeenCalledTimes(1); - }); - }); - - it('passes references to search source parsing function', async () => { - SavedObjectClass = createSavedObjectClass( - { - savedObjectsClient: savedObjectsClientStub, - indexPatterns: dataStartMock.indexPatterns, - search: { - ...dataStartMock.search, - }, - } as unknown as SavedObjectKibanaServices, - startServices, - decoratorRegistry - ); - const savedObject = new SavedObjectClass({ type: 'dashboard', searchSource: true }); - return savedObject.init!().then(async () => { - const searchSourceJSON = JSON.stringify({ - indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index', - filter: [ - { - meta: { - indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index', - }, - }, - ], - }); - const response = { - found: true, - _source: { - kibanaSavedObjectMeta: { - searchSourceJSON, - }, - }, - references: [ - { - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - id: 'my-index-1', - }, - { - name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index', - type: 'index-pattern', - id: 'my-index-2', - }, - ], - }; - await savedObject.applyESResp(response); - expect(dataStartMock.search.searchSource.create).toBeCalledWith({ - filter: [{ meta: { index: 'my-index-2' } }], - index: 'my-index-1', - }); - }); - }); - }); - - describe('config', () => { - it('afterESResp is called', () => { - const afterESRespCallback = jest.fn(); - const config = { - type: 'dashboard', - afterESResp: afterESRespCallback, - }; - - return createInitializedSavedObject(config).then(() => { - expect(afterESRespCallback).toHaveBeenCalled(); - }); - }); - - describe('searchSource', () => { - it('when true, creates index', () => { - const indexPatternId = 'testIndexPattern'; - const afterESRespCallback = jest.fn(); - - const config: SavedObjectConfig = { - type: 'dashboard', - afterESResp: afterESRespCallback, - searchSource: true, - indexPattern: { id: indexPatternId } as DataView, - }; - - stubESResponse( - getMockedDocResponse(indexPatternId, { - attributes: { - title: 'testIndexPattern', - }, - }) - ); - - const savedObject = new SavedObjectClass(config); - savedObject.hydrateIndexPattern = jest.fn().mockImplementation(() => { - const indexPattern = createStubIndexPattern({ - spec: { - id: indexPatternId, - title: indexPatternId, - }, - }); - savedObject.searchSource!.setField('index', indexPattern); - return Promise.resolve(indexPattern); - }); - expect(!!savedObject.searchSource!.getField('index')).toBe(false); - - return savedObject.init!().then(() => { - expect(afterESRespCallback).toHaveBeenCalled(); - const index = savedObject.searchSource!.getField('index'); - expect(index instanceof DataView).toBe(true); - expect(index!.id).toEqual(indexPatternId); - }); - }); - - it('when false, does not create index', () => { - const indexPatternId = 'testIndexPattern'; - const afterESRespCallback = jest.fn(); - - const config: SavedObjectConfig = { - type: 'dashboard', - afterESResp: afterESRespCallback, - searchSource: false, - indexPattern: { id: indexPatternId } as DataView, - }; - - stubESResponse(getMockedDocResponse(indexPatternId)); - - const savedObject = new SavedObjectClass(config); - expect(!!savedObject.searchSource).toBe(false); - - return savedObject.init!().then(() => { - expect(afterESRespCallback).toHaveBeenCalled(); - expect(!!savedObject.searchSource).toBe(false); - }); - }); - }); - - describe('type', () => { - it('that is not specified throws an error', (done) => { - const config = {}; - - const savedObject = new SavedObjectClass(config); - savedObject.init!().catch(() => { - done(); - }); - }); - - it('that is invalid invalid throws an error', () => { - const config = { type: 'notypeexists' }; - - const savedObject = new SavedObjectClass(config); - try { - savedObject.init!(); - expect(false).toBe(true); - } catch (err) { - expect(err).not.toBeNull(); - } - }); - - it('that is valid passes', () => { - const config = { type: 'dashboard' }; - return new SavedObjectClass(config).init!(); - }); - }); - - describe('defaults', () => { - function getTestDefaultConfig(extraOptions: object = {}) { - return { - defaults: { testDefault: 'hi' }, - type: 'dashboard', - ...extraOptions, - }; - } - - function expectDefaultApplied(config: SavedObjectConfig) { - return createInitializedSavedObject(config).then((savedObject) => { - expect(savedObject.defaults).toBe(config.defaults); - }); - } - - describe('applied to object when id', () => { - it('is not specified', () => { - expectDefaultApplied(getTestDefaultConfig()); - }); - - it('is undefined', () => { - expectDefaultApplied(getTestDefaultConfig({ id: undefined })); - }); - - it('is 0', () => { - expectDefaultApplied(getTestDefaultConfig({ id: 0 })); - }); - - it('is false', () => { - expectDefaultApplied(getTestDefaultConfig({ id: false })); - }); - }); - - it('applied to source if an id is given', () => { - const myId = 'myid'; - const customDefault = 'hi'; - const initialOverwriteMeValue = 'this should get overwritten by the server response'; - - const config = { - defaults: { - overwriteMe: initialOverwriteMeValue, - customDefault, - }, - type: 'dashboard', - id: myId, - }; - - const serverValue = 'this should override the initial default value given'; - - const mockDocResponse = getMockedDocResponse(myId, { - attributes: { overwriteMe: serverValue }, - }); - - stubESResponse(mockDocResponse); - - return createInitializedSavedObject(config).then((savedObject) => { - expect(!!savedObject._source).toBe(true); - expect(savedObject.defaults).toBe(config.defaults); - expect(savedObject._source.overwriteMe).toBe(serverValue); - expect(savedObject._source.customDefault).toBe(customDefault); - }); - }); - }); - }); -}); diff --git a/src/plugins/saved_objects/public/saved_object/saved_object.ts b/src/plugins/saved_objects/public/saved_object/saved_object.ts deleted file mode 100644 index cb83021582b2e..0000000000000 --- a/src/plugins/saved_objects/public/saved_object/saved_object.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/** - * @name SavedObject - * - * NOTE: SavedObject seems to track a reference to an object in ES, - * and surface methods for CRUD functionality (save and delete). This seems - * similar to how Backbone Models work. - * - * This class seems to interface with ES primarily through the es Angular - * service and the saved object api. - */ -import { SavedObject, SavedObjectConfig, SavedObjectKibanaServices, StartServices } from '../types'; -import { ISavedObjectDecoratorRegistry } from './decorators'; -import { buildSavedObject } from './helpers/build_saved_object'; - -export function createSavedObjectClass( - services: SavedObjectKibanaServices, - startServices: StartServices, - decoratorRegistry: ISavedObjectDecoratorRegistry -) { - /** - * The SavedObject class is a base class for saved objects loaded from the server and - * provides additional functionality besides loading/saving/deleting/etc. - * - * It is overloaded and configured to provide type-aware functionality. - * @param {*} config - */ - class SavedObjectClass { - constructor(config: SavedObjectConfig = {}) { - // @ts-ignore - const self: SavedObject = this; - buildSavedObject( - self, - config, - services, - startServices, - decoratorRegistry.getOrderedDecorators(services) - ); - } - } - - return SavedObjectClass as new (config: SavedObjectConfig) => SavedObject; -} diff --git a/src/plugins/saved_objects/tsconfig.json b/src/plugins/saved_objects/tsconfig.json index 4dbced6ac31a7..ccec7b43ad9f1 100644 --- a/src/plugins/saved_objects/tsconfig.json +++ b/src/plugins/saved_objects/tsconfig.json @@ -11,7 +11,6 @@ "@kbn/i18n", "@kbn/data-views-plugin", "@kbn/i18n-react", - "@kbn/utility-types", "@kbn/ui-theme", "@kbn/react-kibana-mount", "@kbn/test-jest-helpers", diff --git a/src/plugins/saved_objects_tagging_oss/public/api.mock.ts b/src/plugins/saved_objects_tagging_oss/public/api.mock.ts index 09655c6d28108..07539956c1485 100644 --- a/src/plugins/saved_objects_tagging_oss/public/api.mock.ts +++ b/src/plugins/saved_objects_tagging_oss/public/api.mock.ts @@ -55,8 +55,6 @@ type SavedObjectsTaggingApiUiMock = Omit, const createApiUiMock = () => { const mock: SavedObjectsTaggingApiUiMock = { components: createApiUiComponentsMock(), - // TS is very picky with type guards - hasTagDecoration: jest.fn() as any, getSearchBarFilter: jest.fn(), getTableColumnDefinition: jest.fn(), convertNameToReference: jest.fn(), diff --git a/src/plugins/saved_objects_tagging_oss/public/api.ts b/src/plugins/saved_objects_tagging_oss/public/api.ts index f211250532094..fa7f3665ac023 100644 --- a/src/plugins/saved_objects_tagging_oss/public/api.ts +++ b/src/plugins/saved_objects_tagging_oss/public/api.ts @@ -12,8 +12,6 @@ import { SearchFilterConfig, EuiTableFieldDataColumnType, EuiComboBoxProps } fro import type { FunctionComponent } from 'react'; import { SavedObject, SavedObjectReference } from '@kbn/core/types'; import { SavedObjectsFindOptionsReference } from '@kbn/core/public'; -import { SavedObject as SavedObjectClass } from '@kbn/saved-objects-plugin/public'; -import { TagDecoratedSavedObject } from './decorator'; import { ITagsClient, Tag, TagWithOptionalId } from '../common'; /** @@ -50,11 +48,6 @@ export interface ITagsCache { getState$(params?: { waitForInitialization?: boolean }): Observable; } -/** - * @public - */ -export type SavedObjectTagDecoratorTypeGuard = SavedObjectsTaggingApiUi['hasTagDecoration']; - /** * React components and utility methods to use the SO tagging feature * @@ -72,13 +65,6 @@ export interface SavedObjectsTaggingApiUi { */ getTagList(): Tag[]; - /** - * Type-guard to safely manipulate tag-enhanced `SavedObject` from the `savedObject` plugin. - * - * @param object - */ - hasTagDecoration(object: SavedObjectClass): object is TagDecoratedSavedObject; - /** * Return a filter that can be used to filter by tag with `EuiSearchBar` or EUI tables using `EuiSearchBar`. * diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.mocks.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.mocks.ts deleted file mode 100644 index 5ca655b8a667d..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.mocks.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const injectTagReferencesMock = jest.fn(); -jest.doMock('./inject_tag_references', () => ({ - injectTagReferences: injectTagReferencesMock, -})); - -export const extractTagReferencesMock = jest.fn(); -jest.doMock('./extract_tag_references', () => ({ - extractTagReferences: extractTagReferencesMock, -})); diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.ts deleted file mode 100644 index 37536804e6c87..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.test.ts +++ /dev/null @@ -1,133 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { extractTagReferencesMock, injectTagReferencesMock } from './decorate_config.test.mocks'; - -import { SavedObjectConfig } from '@kbn/saved-objects-plugin/public'; -import { decorateConfig } from './decorate_config'; - -describe('decorateConfig', () => { - afterEach(() => { - extractTagReferencesMock.mockReset(); - injectTagReferencesMock.mockReset(); - }); - - describe('mapping', () => { - it('adds the `__tags` key to the config mapping', () => { - const config: SavedObjectConfig = { - mapping: { - someText: 'text', - someNum: 'number', - }, - }; - - decorateConfig(config); - - expect(config.mapping).toEqual({ - __tags: 'text', - someText: 'text', - someNum: 'number', - }); - }); - - it('adds mapping to the config if missing', () => { - const config: SavedObjectConfig = {}; - - decorateConfig(config); - - expect(config.mapping).toEqual({ - __tags: 'text', - }); - }); - }); - - describe('injectReferences', () => { - it('decorates to only call `injectTagReferences` when not present on the config', () => { - const config: SavedObjectConfig = {}; - - decorateConfig(config); - - const object: any = Symbol('object'); - const references: any = Symbol('referebces'); - - config.injectReferences!(object, references); - - expect(injectTagReferencesMock).toHaveBeenCalledTimes(1); - expect(injectTagReferencesMock).toHaveBeenCalledWith(object, references); - }); - - it('decorates to call both functions when present on the config', () => { - const initialInjectReferences = jest.fn(); - - const config: SavedObjectConfig = { - injectReferences: initialInjectReferences, - }; - - decorateConfig(config); - - const object: any = Symbol('object'); - const references: any = Symbol('references'); - - config.injectReferences!(object, references); - - expect(initialInjectReferences).toHaveBeenCalledTimes(1); - expect(initialInjectReferences).toHaveBeenCalledWith(object, references); - - expect(injectTagReferencesMock).toHaveBeenCalledTimes(1); - expect(injectTagReferencesMock).toHaveBeenCalledWith(object, references); - }); - }); - - describe('extractReferences', () => { - it('decorates to only call `extractTagReference` when not present on the config', () => { - const config: SavedObjectConfig = {}; - - decorateConfig(config); - - const params: any = Symbol('params'); - const expectedReturn = Symbol('return-from-extractTagReferences'); - - extractTagReferencesMock.mockReturnValue(expectedReturn); - - const result = config.extractReferences!(params); - - expect(result).toBe(expectedReturn); - - expect(extractTagReferencesMock).toHaveBeenCalledTimes(1); - expect(extractTagReferencesMock).toHaveBeenCalledWith(params); - }); - - it('decorates to call both functions in order when present on the config', () => { - const initialExtractReferences = jest.fn(); - - const config: SavedObjectConfig = { - extractReferences: initialExtractReferences, - }; - - decorateConfig(config); - - const params: any = Symbol('initial-params'); - const initialReturn = Symbol('return-from-initial-extractReferences'); - const tagReturn = Symbol('return-from-extractTagReferences'); - - initialExtractReferences.mockReturnValue(initialReturn); - extractTagReferencesMock.mockReturnValue(tagReturn); - - const result = config.extractReferences!(params); - - expect(initialExtractReferences).toHaveBeenCalledTimes(1); - expect(initialExtractReferences).toHaveBeenCalledWith(params); - - expect(extractTagReferencesMock).toHaveBeenCalledTimes(1); - expect(extractTagReferencesMock).toHaveBeenCalledWith(initialReturn); - - expect(result).toBe(tagReturn); - }); - }); -}); diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.ts deleted file mode 100644 index 8cdb6a4229d44..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_config.ts +++ /dev/null @@ -1,36 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectConfig } from '@kbn/saved-objects-plugin/public'; -import { injectTagReferences } from './inject_tag_references'; -import { extractTagReferences } from './extract_tag_references'; - -export const decorateConfig = (config: SavedObjectConfig) => { - config.mapping = { - ...config.mapping, - __tags: 'text', - }; - - const initialExtractReferences = config.extractReferences; - const initialInjectReferences = config.injectReferences; - - config.injectReferences = (object, references) => { - if (initialInjectReferences) { - initialInjectReferences(object, references); - } - injectTagReferences(object, references); - }; - - config.extractReferences = (attrsAndRefs) => { - if (initialExtractReferences) { - attrsAndRefs = initialExtractReferences(attrsAndRefs); - } - return extractTagReferences(attrsAndRefs); - }; -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.test.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.test.ts deleted file mode 100644 index a997e7c2591a3..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.test.ts +++ /dev/null @@ -1,41 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { InternalTagDecoratedSavedObject } from './types'; -import { decorateObject } from './decorate_object'; - -const createObject = (): InternalTagDecoratedSavedObject => { - // we really just need TS not to complain here. - return {} as InternalTagDecoratedSavedObject; -}; - -describe('decorateObject', () => { - it('adds the `getTags` method', () => { - const object = createObject(); - object.__tags = ['foo', 'bar']; - - decorateObject(object); - - expect(object.getTags).toBeDefined(); - expect(object.getTags()).toEqual(['foo', 'bar']); - }); - - it('adds the `setTags` method', () => { - const object = createObject(); - object.__tags = ['foo', 'bar']; - - decorateObject(object); - - expect(object.setTags).toBeDefined(); - - object.setTags(['hello', 'dolly']); - - expect(object.getTags()).toEqual(['hello', 'dolly']); - }); -}); diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.ts deleted file mode 100644 index 0c03863b55ea9..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/decorate_object.ts +++ /dev/null @@ -1,22 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { InternalTagDecoratedSavedObject } from './types'; - -/** - * Enhance the object with tag accessors - */ -export const decorateObject = (object: InternalTagDecoratedSavedObject) => { - object.getTags = () => { - return object.__tags ?? []; - }; - object.setTags = (tagIds) => { - object.__tags = tagIds; - }; -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.test.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.test.ts deleted file mode 100644 index 2ac4c4d0db8c2..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.test.ts +++ /dev/null @@ -1,101 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectReference } from '@kbn/core/public'; -import { extractTagReferences } from './extract_tag_references'; - -const ref = (type: string, id: string, name = `ref-to-${type}-${id}`): SavedObjectReference => ({ - id, - type, - name, -}); - -const tagRef = (id: string): SavedObjectReference => ref('tag', id, `tag-${id}`); - -describe('extractTagReferences', () => { - it('generate tag references from the attributes', () => { - const attributes = { - __tags: ['tag-id-1', 'tag-id-2'], - }; - const references: SavedObjectReference[] = []; - - const { references: resultRefs } = extractTagReferences({ - attributes, - references, - }); - - expect(resultRefs).toEqual([tagRef('tag-id-1'), tagRef('tag-id-2')]); - }); - - it('removes the `__tag` property from the attributes', () => { - const attributes = { - someString: 'foo', - someNumber: 42, - __tags: ['tag-id-1', 'tag-id-2'], - }; - const references: SavedObjectReference[] = []; - - const { attributes: resultAttrs } = extractTagReferences({ - attributes, - references, - }); - - expect(resultAttrs).toEqual({ someString: 'foo', someNumber: 42 }); - }); - - it('preserves the other references', () => { - const attributes = { - __tags: ['tag-id-1'], - }; - - const refA = ref('dashboard', 'dash-1'); - const refB = ref('visualization', 'vis-1'); - - const { references: resultRefs } = extractTagReferences({ - attributes, - references: [refA, refB], - }); - - expect(resultRefs).toEqual([refA, refB, tagRef('tag-id-1')]); - }); - - it('does not fail if `attributes` does not contain `__tags`', () => { - const attributes = { - someString: 'foo', - someNumber: 42, - }; - - const refA = ref('dashboard', 'dash-1'); - const refB = ref('visualization', 'vis-1'); - - const { attributes: resultAttrs, references: resultRefs } = extractTagReferences({ - attributes, - references: [refA, refB], - }); - - expect(resultRefs).toEqual([refA, refB]); - expect(resultAttrs).toEqual({ someString: 'foo', someNumber: 42 }); - }); - - it('removes duplicated tags', () => { - const attributes = { - __tags: ['tag-id-1', 'tag-id-1', 'tag-id-1', 'tag-id-1', 'tag-id-2'], - }; - - const { references: resultRefs } = extractTagReferences({ - attributes, - references: [] as SavedObjectReference[], - }); - - expect(resultRefs).toEqual([ - { id: 'tag-id-1', name: 'tag-tag-id-1', type: 'tag' }, - { id: 'tag-id-2', name: 'tag-tag-id-2', type: 'tag' }, - ]); - }); -}); diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.ts deleted file mode 100644 index 35ee2a75a8803..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/extract_tag_references.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectConfig } from '@kbn/saved-objects-plugin/public'; - -/** - * Extract the tag references from the object's attribute - * - * (`extractReferences` is used when persisting the saved object to the backend) - */ -export const extractTagReferences: Required['extractReferences'] = ({ - attributes, - references, -}) => { - const { __tags, ...otherAttributes } = attributes; - const tags = [...new Set(__tags as string[])] ?? []; - return { - attributes: otherAttributes, - references: [ - ...references, - ...tags.map((tagId) => ({ - id: tagId, - type: 'tag', - name: `tag-${tagId}`, - })), - ], - }; -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/factory.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/factory.ts deleted file mode 100644 index 003fa5c626b09..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/factory.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectDecoratorFactory } from '@kbn/saved-objects-plugin/public'; -import { InternalTagDecoratedSavedObject } from './types'; -import { decorateConfig } from './decorate_config'; -import { decorateObject } from './decorate_object'; - -export const decoratorId = 'tag'; - -export const tagDecoratorFactory: SavedObjectDecoratorFactory< - InternalTagDecoratedSavedObject -> = () => { - return { - getId: () => decoratorId, - decorateConfig, - decorateObject, - }; -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/index.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/index.ts deleted file mode 100644 index e2c9f0dcf14cf..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/index.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectDecoratorConfig } from '@kbn/saved-objects-plugin/public'; -import { tagDecoratorFactory, decoratorId } from './factory'; -import { InternalTagDecoratedSavedObject } from './types'; - -export type { TagDecoratedSavedObject } from './types'; - -export const tagDecoratorConfig: SavedObjectDecoratorConfig = { - id: decoratorId, - priority: 100, - factory: tagDecoratorFactory, -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.test.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.test.ts deleted file mode 100644 index 2eb3db3937b86..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.test.ts +++ /dev/null @@ -1,60 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectReference } from '@kbn/core/public'; -import { injectTagReferences } from './inject_tag_references'; -import { InternalTagDecoratedSavedObject } from './types'; - -const ref = (type: string, id: string): SavedObjectReference => ({ - id, - type, - name: `ref-to-${type}-${id}`, -}); - -const tagRef = (id: string) => ref('tag', id); - -const createObject = (): InternalTagDecoratedSavedObject => { - // we really just need TS not to complain here. - return {} as InternalTagDecoratedSavedObject; -}; - -describe('injectTagReferences', () => { - let object: InternalTagDecoratedSavedObject; - - beforeEach(() => { - object = createObject(); - }); - - it('injects the `tag` references to the `__tags` field', () => { - const references = [tagRef('tag-id-1'), tagRef('tag-id-2')]; - - injectTagReferences(object, references); - - expect(object.__tags).toEqual(['tag-id-1', 'tag-id-2']); - }); - - it('only process the tag references', () => { - const references = [ - tagRef('tag-id-1'), - ref('dashboard', 'foo'), - tagRef('tag-id-2'), - ref('dashboard', 'baz'), - ]; - - injectTagReferences(object, references); - - expect(object.__tags).toEqual(['tag-id-1', 'tag-id-2']); - }); - - it('injects an empty list when not tag references are present', () => { - injectTagReferences(object, [ref('dashboard', 'foo'), ref('dashboard', 'baz')]); - - expect(object.__tags).toEqual([]); - }); -}); diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.ts deleted file mode 100644 index fd550a81837f9..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/inject_tag_references.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObjectConfig } from '@kbn/saved-objects-plugin/public'; -import { InternalTagDecoratedSavedObject } from './types'; - -/** - * Inject the tags back into the object's references - * - * (`injectReferences`) is used when fetching the object from the backend - */ -export const injectTagReferences: Required['injectReferences'] = ( - object, - references = [] -) => { - (object as unknown as InternalTagDecoratedSavedObject).__tags = references - .filter(({ type }) => type === 'tag') - .map(({ id }) => id); -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/decorator/types.ts b/src/plugins/saved_objects_tagging_oss/public/decorator/types.ts deleted file mode 100644 index b50f1b183ae39..0000000000000 --- a/src/plugins/saved_objects_tagging_oss/public/decorator/types.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SavedObject } from '@kbn/saved-objects-plugin/public'; - -/** - * @public - */ -export type TagDecoratedSavedObject = SavedObject & { - getTags(): string[]; - setTags(tags: string[]): void; -}; - -/** - * @internal - */ -export type InternalTagDecoratedSavedObject = TagDecoratedSavedObject & { - __tags: string[]; -}; diff --git a/src/plugins/saved_objects_tagging_oss/public/index.ts b/src/plugins/saved_objects_tagging_oss/public/index.ts index 58dce1bd20842..b754d763427c8 100644 --- a/src/plugins/saved_objects_tagging_oss/public/index.ts +++ b/src/plugins/saved_objects_tagging_oss/public/index.ts @@ -23,11 +23,8 @@ export type { ParsedSearchQuery, ParseSearchQueryOptions, SavedObjectSaveModalTagSelectorComponentProps, - SavedObjectTagDecoratorTypeGuard, GetTableColumnDefinitionOptions, } from './api'; -export type { TagDecoratedSavedObject } from './decorator'; - export const plugin = (initializerContext: PluginInitializerContext) => new SavedObjectTaggingOssPlugin(initializerContext); diff --git a/src/plugins/saved_objects_tagging_oss/public/plugin.test.ts b/src/plugins/saved_objects_tagging_oss/public/plugin.test.ts index 7c26f5a9a8289..bb3f0f0e78f83 100644 --- a/src/plugins/saved_objects_tagging_oss/public/plugin.test.ts +++ b/src/plugins/saved_objects_tagging_oss/public/plugin.test.ts @@ -8,8 +8,6 @@ */ import { coreMock } from '@kbn/core/public/mocks'; -import { savedObjectsPluginMock } from '@kbn/saved-objects-plugin/public/mocks'; -import { tagDecoratorConfig } from './decorator'; import { taggingApiMock } from './api.mock'; import { SavedObjectTaggingOssPlugin } from './plugin'; @@ -22,23 +20,6 @@ describe('SavedObjectTaggingOssPlugin', () => { plugin = new SavedObjectTaggingOssPlugin(coreMock.createPluginInitializerContext()); }); - describe('#setup', () => { - it('registers the tag SO decorator if the `savedObjects` plugin is present', () => { - const savedObjects = savedObjectsPluginMock.createSetupContract(); - - plugin.setup(coreSetup, { savedObjects }); - - expect(savedObjects.registerDecorator).toHaveBeenCalledTimes(1); - expect(savedObjects.registerDecorator).toHaveBeenCalledWith(tagDecoratorConfig); - }); - - it('does not fail if the `savedObjects` plugin is not present', () => { - expect(() => { - plugin.setup(coreSetup, {}); - }).not.toThrow(); - }); - }); - describe('#start', () => { let coreStart: ReturnType; @@ -54,7 +35,7 @@ describe('SavedObjectTaggingOssPlugin', () => { it('returns the tagging API if registered', async () => { const taggingApi = taggingApiMock.create(); - const { registerTaggingApi } = plugin.setup(coreSetup, {}); + const { registerTaggingApi } = plugin.setup(coreSetup); registerTaggingApi(Promise.resolve(taggingApi)); @@ -66,7 +47,7 @@ describe('SavedObjectTaggingOssPlugin', () => { expect(getTaggingApi()).toStrictEqual(taggingApi); }); it('does not return the tagging API if not registered', async () => { - plugin.setup(coreSetup, {}); + plugin.setup(coreSetup); await nextTick(); @@ -76,7 +57,7 @@ describe('SavedObjectTaggingOssPlugin', () => { expect(getTaggingApi()).toBeUndefined(); }); it('does not return the tagging API if resolution promise rejects', async () => { - const { registerTaggingApi } = plugin.setup(coreSetup, {}); + const { registerTaggingApi } = plugin.setup(coreSetup); registerTaggingApi(Promise.reject(new Error('something went bad'))); diff --git a/src/plugins/saved_objects_tagging_oss/public/plugin.ts b/src/plugins/saved_objects_tagging_oss/public/plugin.ts index 94a77dcdf2610..c6097b447ade7 100644 --- a/src/plugins/saved_objects_tagging_oss/public/plugin.ts +++ b/src/plugins/saved_objects_tagging_oss/public/plugin.ts @@ -8,29 +8,18 @@ */ import { CoreSetup, CoreStart, PluginInitializerContext, Plugin } from '@kbn/core/public'; -import { SavedObjectSetup } from '@kbn/saved-objects-plugin/public'; import { SavedObjectTaggingOssPluginSetup, SavedObjectTaggingOssPluginStart } from './types'; import { SavedObjectsTaggingApi } from './api'; -import { tagDecoratorConfig } from './decorator'; - -interface SetupDeps { - savedObjects?: SavedObjectSetup; -} export class SavedObjectTaggingOssPlugin - implements - Plugin + implements Plugin { private apiRegistered = false; private api?: SavedObjectsTaggingApi; constructor(context: PluginInitializerContext) {} - public setup({}: CoreSetup, { savedObjects }: SetupDeps) { - if (savedObjects) { - savedObjects.registerDecorator(tagDecoratorConfig); - } - + public setup({}: CoreSetup) { return { registerTaggingApi: (provider: Promise) => { if (this.apiRegistered) { diff --git a/src/plugins/saved_objects_tagging_oss/tsconfig.json b/src/plugins/saved_objects_tagging_oss/tsconfig.json index 6b98cba4cbd12..fa0436bab9161 100644 --- a/src/plugins/saved_objects_tagging_oss/tsconfig.json +++ b/src/plugins/saved_objects_tagging_oss/tsconfig.json @@ -9,7 +9,6 @@ ], "kbn_references": [ "@kbn/core", - "@kbn/saved-objects-plugin", ], "exclude": [ "target/**/*", diff --git a/src/plugins/visualizations/public/mocks.ts b/src/plugins/visualizations/public/mocks.ts index fbc61c871bd59..626bab7b9e0ed 100644 --- a/src/plugins/visualizations/public/mocks.ts +++ b/src/plugins/visualizations/public/mocks.ts @@ -17,7 +17,6 @@ import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { indexPatternEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks'; import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; -import { savedObjectsPluginMock } from '@kbn/saved-objects-plugin/public/mocks'; import { urlForwardingPluginMock } from '@kbn/url-forwarding-plugin/public/mocks'; import { navigationPluginMock } from '@kbn/navigation-plugin/public/mocks'; import { presentationUtilPluginMock } from '@kbn/presentation-util-plugin/public/mocks'; @@ -77,7 +76,6 @@ const createInstance = async () => { embeddable: embeddablePluginMock.createStartContract(), spaces: spacesPluginMock.createStartContract(), savedObjectsClient: coreMock.createStart().savedObjects.client, - savedObjects: savedObjectsPluginMock.createStartContract(), savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(), savedSearch: savedSearchPluginMock.createStartContract(), navigation: navigationPluginMock.createStartContract(), diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts index 24a2c488e0f79..fcb3dc5137161 100644 --- a/src/plugins/visualizations/public/plugin.ts +++ b/src/plugins/visualizations/public/plugin.ts @@ -38,7 +38,6 @@ import type { SavedObjectsClientContract, } from '@kbn/core/public'; import { UiActionsStart, UiActionsSetup, ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public'; -import type { SavedObjectsStart } from '@kbn/saved-objects-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { Setup as InspectorSetup, @@ -166,7 +165,6 @@ export interface VisualizationsStartDeps { application: ApplicationStart; navigation: NavigationStart; presentationUtil: PresentationUtilPluginStart; - savedObjects: SavedObjectsStart; savedObjectsClient: SavedObjectsClientContract; savedSearch: SavedSearchPublicPluginStart; spaces?: SpacesPluginStart; diff --git a/x-pack/plugins/saved_objects_tagging/public/ui_api/has_tag_decoration.ts b/x-pack/plugins/saved_objects_tagging/public/ui_api/has_tag_decoration.ts deleted file mode 100644 index 6dccf97f0a672..0000000000000 --- a/x-pack/plugins/saved_objects_tagging/public/ui_api/has_tag_decoration.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - SavedObjectsTaggingApiUi, - TagDecoratedSavedObject, -} from '@kbn/saved-objects-tagging-oss-plugin/public'; - -export const hasTagDecoration: SavedObjectsTaggingApiUi['hasTagDecoration'] = ( - object -): object is TagDecoratedSavedObject => { - return 'getTags' in object && 'setTags' in object; -}; diff --git a/x-pack/plugins/saved_objects_tagging/public/ui_api/index.ts b/x-pack/plugins/saved_objects_tagging/public/ui_api/index.ts index d25b04dd1002c..635e2e5af0440 100644 --- a/x-pack/plugins/saved_objects_tagging/public/ui_api/index.ts +++ b/x-pack/plugins/saved_objects_tagging/public/ui_api/index.ts @@ -21,7 +21,6 @@ import { buildGetSearchBarFilter } from './get_search_bar_filter'; import { buildParseSearchQuery } from './parse_search_query'; import { buildConvertNameToReference } from './convert_name_to_reference'; import { buildGetTagList } from './get_tag_list'; -import { hasTagDecoration } from './has_tag_decoration'; interface GetUiApiOptions extends StartServices { capabilities: TagsCapabilities; @@ -50,7 +49,6 @@ export const getUiApi = ({ getSearchBarFilter: buildGetSearchBarFilter({ getTagList }), parseSearchQuery: buildParseSearchQuery({ cache }), convertNameToReference: buildConvertNameToReference({ cache }), - hasTagDecoration, getTagIdsFromReferences, getTagIdFromName: (tagName: string) => convertTagNameToId(tagName, cache.getState()), updateTagsReferences, diff --git a/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx b/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx index 0feb3b2c9fc21..6af01088b70db 100644 --- a/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx @@ -16,7 +16,6 @@ import type { ScopedHistory } from '@kbn/core/public'; import { coreMock, themeServiceMock } from '@kbn/core/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import { savedObjectsPluginMock } from '@kbn/saved-objects-plugin/public/mocks'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; import type { SharePluginStart } from '@kbn/share-plugin/public'; @@ -88,7 +87,6 @@ const appDependencies: AppDependencies = { theme: themeServiceMock.createStartContract(), http: coreSetup.http, history: {} as ScopedHistory, - savedObjectsPlugin: savedObjectsPluginMock.createStartContract(), share: { urlGenerators: { getUrlGenerator: jest.fn() } } as unknown as SharePluginStart, ml: {} as GetMlSharedImportsReturnType, triggersActionsUi: {} as jest.Mocked, diff --git a/x-pack/plugins/transform/public/app/app_dependencies.tsx b/x-pack/plugins/transform/public/app/app_dependencies.tsx index ebb65f58a4093..1f8b2373f0f7d 100644 --- a/x-pack/plugins/transform/public/app/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/app_dependencies.tsx @@ -19,7 +19,6 @@ import type { ScopedHistory, ThemeServiceStart, } from '@kbn/core/public'; -import type { SavedObjectsStart as SavedObjectsPluginStart } from '@kbn/saved-objects-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; @@ -60,7 +59,6 @@ export interface AppDependencies { overlays: OverlayStart; theme: ThemeServiceStart; history: ScopedHistory; - savedObjectsPlugin: SavedObjectsPluginStart; share: SharePluginStart; ml: GetMlSharedImportsReturnType; spaces?: SpacesPluginStart; diff --git a/x-pack/plugins/transform/public/app/mount_management_section.ts b/x-pack/plugins/transform/public/app/mount_management_section.ts index e28275d203990..8d59c9ce2d0f2 100644 --- a/x-pack/plugins/transform/public/app/mount_management_section.ts +++ b/x-pack/plugins/transform/public/app/mount_management_section.ts @@ -85,7 +85,6 @@ export async function mountManagementSection( uiSettings, settings, history, - savedObjectsPlugin: plugins.savedObjects, share, spaces, ml: await getMlSharedImports(), diff --git a/x-pack/plugins/transform/public/plugin.ts b/x-pack/plugins/transform/public/plugin.ts index f1677bbcb7c78..07bda2b5400b1 100644 --- a/x-pack/plugins/transform/public/plugin.ts +++ b/x-pack/plugins/transform/public/plugin.ts @@ -11,7 +11,6 @@ import type { CoreSetup } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; -import type { SavedObjectsStart } from '@kbn/saved-objects-plugin/public'; import type { ManagementSetup } from '@kbn/management-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { SpacesApi } from '@kbn/spaces-plugin/public'; @@ -37,7 +36,6 @@ export interface PluginsDependencies { dataViews: DataViewsPublicPluginStart; management: ManagementSetup; home: HomePublicPluginSetup; - savedObjects: SavedObjectsStart; savedSearch: SavedSearchPublicPluginStart; share: SharePluginStart; spaces?: SpacesApi; diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 9b1abbd589a83..e3ccb0cc1d403 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -24,7 +24,6 @@ "@kbn/alerting-plugin", "@kbn/data-views-plugin", "@kbn/home-plugin", - "@kbn/saved-objects-plugin", "@kbn/management-plugin", "@kbn/share-plugin", "@kbn/spaces-plugin",