From c59dddfa452498b78877009c644690197356687d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 11 Dec 2024 09:27:03 -0700 Subject: [PATCH] [embeddable] remove legacy embeddable test samples (#203678) Remove legacy embeddable test constructs. PR removes tests that use test samples and some code that could be easily removed. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../component/grid/dashboard_grid.test.tsx | 5 +- .../edit_legacy_embeddable.test.tsx | 125 --- .../compatibility/edit_legacy_embeddable.tsx | 99 --- .../compatibility/legacy_embeddable_to_api.ts | 21 +- .../link_legacy_embeddable.test.ts | 173 ---- .../compatibility/link_legacy_embeddable.ts | 67 -- .../unlink_legacy_embeddable.test.ts | 141 --- .../compatibility/unlink_legacy_embeddable.ts | 50 -- .../lib/embeddables/embeddable.test.tsx | 163 ---- .../embeddables/contact_card/contact_card.tsx | 91 -- .../contact_card/contact_card_embeddable.tsx | 108 --- .../contact_card_embeddable_factory.tsx | 85 -- .../contact_card_embeddable_react.tsx | 20 - .../contact_card_embeddable_react_factory.ts | 29 - .../contact_card_exportable_embeddable.tsx | 37 - ...act_card_exportable_embeddable_factory.tsx | 81 -- .../contact_card/contact_card_initializer.tsx | 88 -- ...riptive_contact_card_embeddable_factory.ts | 44 - .../embeddables/contact_card/index.ts | 18 - .../slow_contact_card_embeddable_factory.ts | 46 - .../embeddables/empty_embeddable.tsx | 21 - .../embeddables/filterable_container.tsx | 52 -- .../filterable_container_factory.ts | 42 - .../embeddables/filterable_embeddable.tsx | 42 - .../filterable_embeddable_factory.ts | 37 - .../embeddables/hello_world_container.tsx | 72 -- .../hello_world_container_component.tsx | 100 --- .../lib/test_samples/embeddables/index.ts | 20 - .../embeddables/time_range_container.ts | 54 -- .../embeddables/time_range_embeddable.ts | 37 - .../time_range_embeddable_factory.ts | 33 - .../public/lib/test_samples/index.ts | 10 - .../embeddable/public/tests/container.test.ts | 817 ------------------ .../public/tests/explicit_input.test.ts | 128 --- .../tests/get_embeddable_factories.test.ts | 40 - .../embeddable/public/tests/helpers.ts | 109 --- src/plugins/embeddable/tsconfig.json | 1 - .../translations/translations/fr-FR.json | 3 - .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - 40 files changed, 14 insertions(+), 3101 deletions(-) delete mode 100644 src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.test.tsx delete mode 100644 src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.tsx delete mode 100644 src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.test.ts delete mode 100644 src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.ts delete mode 100644 src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.test.ts delete mode 100644 src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.ts delete mode 100644 src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable_factory.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_initializer.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/descriptive_contact_card_embeddable_factory.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/empty_embeddable.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container_factory.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable_factory.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/index.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_container.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable_factory.ts delete mode 100644 src/plugins/embeddable/public/lib/test_samples/index.ts delete mode 100644 src/plugins/embeddable/public/tests/container.test.ts delete mode 100644 src/plugins/embeddable/public/tests/explicit_input.test.ts delete mode 100644 src/plugins/embeddable/public/tests/get_embeddable_factories.test.ts delete mode 100644 src/plugins/embeddable/public/tests/helpers.ts diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx index 8700161711e17..543d6b7456270 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid.test.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { CONTACT_CARD_EMBEDDABLE } from '@kbn/embeddable-plugin/public/lib/test_samples/embeddables'; import { DashboardGrid } from './dashboard_grid'; import { buildMockDashboardApi } from '../../../mocks'; @@ -50,12 +49,12 @@ jest.mock('./dashboard_grid_item', () => { const PANELS = { '1': { gridData: { x: 0, y: 0, w: 6, h: 6, i: '1' }, - type: CONTACT_CARD_EMBEDDABLE, + type: 'lens', explicitInput: { id: '1' }, }, '2': { gridData: { x: 6, y: 6, w: 6, h: 6, i: '2' }, - type: CONTACT_CARD_EMBEDDABLE, + type: 'lens', explicitInput: { id: '2' }, }, }; diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.test.tsx b/src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.test.tsx deleted file mode 100644 index 4def23c8801c6..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.test.tsx +++ /dev/null @@ -1,125 +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 { of } from 'rxjs'; - -import { embeddablePluginMock } from '../../../mocks'; -import { applicationServiceMock } from '@kbn/core/public/mocks'; -import { Embeddable, EmbeddableInput, ViewMode } from '../..'; -import { canEditEmbeddable, editLegacyEmbeddable } from './edit_legacy_embeddable'; -import { ContactCardEmbeddable } from '../../test_samples'; -import { core, embeddableStart } from '../../../kibana_services'; - -const applicationMock = applicationServiceMock.createStartContract(); -const stateTransferMock = embeddablePluginMock.createStartContract().getStateTransfer(); - -// mock app id -core.application.currentAppId$ = of('superCoolCurrentApp'); - -class EditableEmbeddable extends Embeddable { - public readonly type = 'EDITABLE_EMBEDDABLE'; - - constructor(input: EmbeddableInput, editable: boolean) { - super(input, { - editUrl: 'www.google.com', - editable, - }); - } - - public reload() {} -} - -test('canEditEmbeddable returns true when edit url is available, in edit mode and editable', () => { - expect( - canEditEmbeddable(new EditableEmbeddable({ id: '123', viewMode: ViewMode.EDIT }, true)) - ).toBe(true); -}); - -test('canEditEmbeddable returns false when edit url is not available', async () => { - const embeddable = new ContactCardEmbeddable( - { - id: '123', - firstName: 'sue', - viewMode: ViewMode.EDIT, - }, - { - execAction: () => Promise.resolve(undefined), - } - ); - expect(canEditEmbeddable(embeddable)).toBe(false); -}); - -test('canEditEmbeddable returns false when edit url is available but in view mode', async () => { - expect( - canEditEmbeddable( - new EditableEmbeddable( - { - id: '123', - viewMode: ViewMode.VIEW, - }, - true - ) - ) - ).toBe(false); -}); - -test('canEditEmbeddable returns false when edit url is available, in edit mode, but not editable', async () => { - expect( - canEditEmbeddable( - new EditableEmbeddable( - { - id: '123', - viewMode: ViewMode.EDIT, - }, - false - ) - ) - ).toBe(false); -}); - -test('getEditHref returns the edit url', async () => { - const embeddable = new EditableEmbeddable({ id: '123', viewMode: ViewMode.EDIT }, true); - expect(await embeddable.getEditHref()).toBe(embeddable.getOutput().editUrl); -}); - -test('redirects to app using state transfer', async () => { - embeddableStart.getStateTransfer = jest.fn().mockReturnValue(stateTransferMock); - - applicationMock.currentAppId$ = of('superCoolCurrentApp'); - const testPath = '/test-path'; - const embeddable = new EditableEmbeddable( - { - id: '123', - viewMode: ViewMode.EDIT, - coolInput1: 1, - coolInput2: 2, - } as unknown as EmbeddableInput, - true - ); - embeddable.getOutput = jest.fn(() => ({ editApp: 'ultraVisualize', editPath: '/123' })); - embeddable.getAppContext = jest.fn().mockReturnValue({ - getCurrentPath: () => testPath, - }); - await editLegacyEmbeddable(embeddable); - expect(stateTransferMock.navigateToEditor).toHaveBeenCalledWith('ultraVisualize', { - path: '/123', - state: { - originatingApp: 'superCoolCurrentApp', - embeddableId: '123', - valueInput: { - id: '123', - viewMode: ViewMode.EDIT, - coolInput1: 1, - coolInput2: 2, - }, - originatingPath: testPath, - searchSessionId: undefined, - }, - }); -}); diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.tsx deleted file mode 100644 index e99bbcfca22ef..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/edit_legacy_embeddable.tsx +++ /dev/null @@ -1,99 +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 { firstValueFrom } from 'rxjs'; -import { LegacyCompatibleEmbeddable } from '../../../embeddable_panel/types'; -import { core, embeddableStart } from '../../../kibana_services'; -import { Container } from '../../containers'; -import { EmbeddableFactoryNotFoundError } from '../../errors'; -import { EmbeddableEditorState } from '../../state_transfer'; -import { isExplicitInputWithAttributes } from '../embeddable_factory'; -import { EmbeddableInput } from '../i_embeddable'; - -const getExplicitInput = (embeddable: LegacyCompatibleEmbeddable) => - (embeddable.getRoot() as Container)?.getInput()?.panels?.[embeddable.id]?.explicitInput ?? - embeddable.getInput(); - -const getAppTarget = async (embeddable: LegacyCompatibleEmbeddable) => { - const app = embeddable ? embeddable.getOutput().editApp : undefined; - const path = embeddable ? embeddable.getOutput().editPath : undefined; - if (!app || !path) return; - - const currentAppId = await firstValueFrom(core.application.currentAppId$); - if (!currentAppId) return { app, path }; - - const state: EmbeddableEditorState = { - originatingApp: currentAppId, - valueInput: getExplicitInput(embeddable), - embeddableId: embeddable.id, - searchSessionId: embeddable.getInput().searchSessionId, - originatingPath: embeddable.getAppContext()?.getCurrentPath?.(), - }; - return { app, path, state }; -}; - -export const editLegacyEmbeddable = async (embeddable: LegacyCompatibleEmbeddable) => { - const { editableWithExplicitInput } = embeddable.getOutput(); - - if (editableWithExplicitInput) { - const factory = embeddableStart.getEmbeddableFactory(embeddable.type); - if (!factory) { - throw new EmbeddableFactoryNotFoundError(embeddable.type); - } - - const oldExplicitInput = embeddable.getExplicitInput(); - let newExplicitInput: Partial; - try { - const explicitInputReturn = await factory.getExplicitInput( - oldExplicitInput, - embeddable.parent - ); - newExplicitInput = isExplicitInputWithAttributes(explicitInputReturn) - ? explicitInputReturn.newInput - : explicitInputReturn; - } catch (e) { - // error likely means user canceled editing - return; - } - embeddable.parent?.replaceEmbeddable(embeddable.id, newExplicitInput); - return; - } - - const appTarget = await getAppTarget(embeddable); - const stateTransfer = embeddableStart.getStateTransfer(); - if (appTarget) { - if (stateTransfer && appTarget.state) { - await stateTransfer.navigateToEditor(appTarget.app, { - path: appTarget.path, - state: appTarget.state, - }); - } else { - await core.application.navigateToApp(appTarget.app, { path: appTarget.path }); - } - return; - } - - const href = embeddable.getOutput().editUrl; - if (href) { - window.location.href = href; - return; - } -}; - -export const canEditEmbeddable = (embeddable: LegacyCompatibleEmbeddable) => { - return Boolean( - embeddable && - embeddable.getInput().viewMode === 'edit' && - embeddable.getOutput().editable && - !embeddable.getOutput().inlineEditable && - (embeddable.getOutput().editUrl || - (embeddable.getOutput().editApp && embeddable.getOutput().editPath) || - embeddable.getOutput().editableWithExplicitInput) - ); -}; diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/legacy_embeddable_to_api.ts b/src/plugins/embeddable/public/lib/embeddables/compatibility/legacy_embeddable_to_api.ts index daab774d7f35d..63c1a6593478b 100644 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/legacy_embeddable_to_api.ts +++ b/src/plugins/embeddable/public/lib/embeddables/compatibility/legacy_embeddable_to_api.ts @@ -37,14 +37,11 @@ import { IEmbeddable, LegacyEmbeddableAPI, } from '../i_embeddable'; -import { canEditEmbeddable, editLegacyEmbeddable } from './edit_legacy_embeddable'; import { embeddableInputToSubject, embeddableOutputToSubject, viewModeToSubject, } from './embeddable_compatibility_utils'; -import { canLinkLegacyEmbeddable, linkLegacyEmbeddable } from './link_legacy_embeddable'; -import { canUnlinkLegacyEmbeddable, unlinkLegacyEmbeddable } from './unlink_legacy_embeddable'; export type CommonLegacyInput = EmbeddableInput & { savedObjectId?: string; timeRange: TimeRange }; export type CommonLegacyOutput = EmbeddableOutput & { indexPatterns: DataView[] }; @@ -93,13 +90,15 @@ export const legacyEmbeddableToApi = ( /** * Support editing of legacy embeddables */ - const onEdit = () => editLegacyEmbeddable(embeddable); + const onEdit = () => { + throw new Error('Edit legacy embeddable not supported'); + }; const getTypeDisplayName = () => embeddableStart.getEmbeddableFactory(embeddable.type)?.getDisplayName() ?? i18n.translate('embeddableApi.compatibility.defaultTypeDisplayName', { defaultMessage: 'chart', }); - const isEditingEnabled = () => canEditEmbeddable(embeddable); + const isEditingEnabled = () => false; /** * Performance tracking @@ -286,11 +285,15 @@ export const legacyEmbeddableToApi = ( panelDescription, defaultPanelDescription, - canLinkToLibrary: () => canLinkLegacyEmbeddable(embeddable), - linkToLibrary: () => linkLegacyEmbeddable(embeddable), + canLinkToLibrary: async () => false, + linkToLibrary: () => { + throw new Error('Link to library not supported for legacy embeddable'); + }, - canUnlinkFromLibrary: () => canUnlinkLegacyEmbeddable(embeddable), - unlinkFromLibrary: () => unlinkLegacyEmbeddable(embeddable), + canUnlinkFromLibrary: async () => false, + unlinkFromLibrary: () => { + throw new Error('Unlink from library not supported for legacy embeddable'); + }, savedObjectId, }, diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.test.ts b/src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.test.ts deleted file mode 100644 index e0a546a18969d..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.test.ts +++ /dev/null @@ -1,173 +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 { EmbeddableInput, ErrorEmbeddable, IContainer, SavedObjectEmbeddableInput } from '../..'; -import { core } from '../../../kibana_services'; -import { embeddablePluginMock } from '../../../mocks'; -import { createHelloWorldContainerAndEmbeddable } from '../../../tests/helpers'; -import { ReferenceOrValueEmbeddable } from '../../reference_or_value_embeddable'; -import { - ContactCardEmbeddable, - ContactCardEmbeddableFactory, - ContactCardEmbeddableInput, -} from '../../test_samples'; -import { ViewMode } from '../../types'; -import { CommonLegacyEmbeddable } from './legacy_embeddable_to_api'; -import { canLinkLegacyEmbeddable, linkLegacyEmbeddable } from './link_legacy_embeddable'; - -let container: IContainer; -let embeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable; -const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); - -const defaultCapabilities = { - advancedSettings: {}, - visualize: { save: true }, - maps: { save: true }, - navLinks: {}, -}; - -beforeEach(async () => { - const result = await createHelloWorldContainerAndEmbeddable(); - container = result.container; - embeddable = embeddablePluginMock.mockRefOrValEmbeddable< - ContactCardEmbeddable, - ContactCardEmbeddableInput - >(result.embeddable, { - mockedByReferenceInput: { savedObjectId: 'testSavedObjectId', id: result.embeddable.id }, - mockedByValueInput: { firstName: 'Kibanana', id: result.embeddable.id }, - }); - embeddable.updateInput({ viewMode: ViewMode.EDIT }); -}); - -const assignDefaultCapabilities = () => { - Object.defineProperty(core.application, 'capabilities', { - value: defaultCapabilities, - }); -}; - -test('Cannot link an Error Embeddable to the library', async () => { - assignDefaultCapabilities(); - const errorEmbeddable = new ErrorEmbeddable( - 'Wow what an awful error', - { id: ' 404' }, - embeddable.getRoot() as IContainer - ); - expect(await canLinkLegacyEmbeddable(errorEmbeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Cannot link an ES|QL Embeddable to the library', async () => { - assignDefaultCapabilities(); - const filterableEmbeddable = embeddablePluginMock.mockFilterableEmbeddable(embeddable, { - getFilters: () => [], - getQuery: () => ({ - esql: 'from logstash-* | limit 10', - }), - }); - expect( - await canLinkLegacyEmbeddable(filterableEmbeddable as unknown as CommonLegacyEmbeddable) - ).toBe(false); -}); - -test('Cannot link a visualize embeddable to the library without visualize save permissions', async () => { - Object.defineProperty(core.application, 'capabilities', { - value: { ...defaultCapabilities, visualize: { save: false } }, - }); - expect(await canLinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Can link an embeddable to the library when it has value type input', async () => { - assignDefaultCapabilities(); - embeddable.updateInput(await embeddable.getInputAsValueType()); - expect(await canLinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe(true); -}); - -test('Cannot link an embedable when its input is by reference', async () => { - assignDefaultCapabilities(); - embeddable.updateInput(await embeddable.getInputAsRefType()); - expect(await canLinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Cannot link an embedable when view mode is set to view', async () => { - assignDefaultCapabilities(); - embeddable.updateInput(await embeddable.getInputAsRefType()); - embeddable.updateInput({ viewMode: ViewMode.VIEW }); - expect(await canLinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Cannot link an embedable when it is not a child of a Dashboard container', async () => { - assignDefaultCapabilities(); - let orphanContactCard = await embeddableFactory.create({ - id: 'orphanContact', - firstName: 'Orphan', - }); - - orphanContactCard = embeddablePluginMock.mockRefOrValEmbeddable< - ContactCardEmbeddable, - ContactCardEmbeddableInput - >(orphanContactCard, { - mockedByReferenceInput: { savedObjectId: 'test', id: orphanContactCard.id }, - mockedByValueInput: { firstName: 'Kibanana', id: orphanContactCard.id }, - }); - expect( - await canLinkLegacyEmbeddable(orphanContactCard as unknown as CommonLegacyEmbeddable) - ).toBe(false); -}); - -test('Linking an embeddable replaces embeddableId and retains panel count', async () => { - assignDefaultCapabilities(); - const dashboard = embeddable.getRoot() as IContainer; - const originalPanelCount = Object.keys(dashboard.getInput().panels).length; - const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); - - await linkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable); - expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount); - - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - expect(newPanelId).toBeDefined(); - const newPanel = container.getInput().panels[newPanelId!]; - expect(newPanel.type).toEqual(embeddable.type); -}); - -test('Link legacy embeddable returns reference type input', async () => { - assignDefaultCapabilities(); - const complicatedAttributes = { - attribute1: 'The best attribute', - attribute2: 22, - attribute3: ['array', 'of', 'strings'], - attribute4: { nestedattribute: 'hello from the nest' }, - }; - - embeddable = embeddablePluginMock.mockRefOrValEmbeddable(embeddable, { - mockedByReferenceInput: { savedObjectId: 'testSavedObjectId', id: embeddable.id }, - mockedByValueInput: { attributes: complicatedAttributes, id: embeddable.id } as EmbeddableInput, - }); - const dashboard = embeddable.getRoot() as IContainer; - const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); - await linkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable); - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - expect(newPanelId).toBeDefined(); - const newPanel = container.getInput().panels[newPanelId!]; - expect(newPanel.type).toEqual(embeddable.type); - expect((newPanel.explicitInput as unknown as { attributes: unknown }).attributes).toBeUndefined(); - expect((newPanel.explicitInput as SavedObjectEmbeddableInput).savedObjectId).toBe( - 'testSavedObjectId' - ); -}); diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.ts deleted file mode 100644 index 2126d1eff764e..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/link_legacy_embeddable.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 type { AggregateQuery } from '@kbn/es-query'; -import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { apiIsPresentationContainer } from '@kbn/presentation-containers'; -import { core } from '../../../kibana_services'; -import { PanelNotFoundError } from '../../errors'; -import { isFilterableEmbeddable } from '../../filterable_embeddable'; -import { isReferenceOrValueEmbeddable } from '../../reference_or_value_embeddable'; -import { isErrorEmbeddable } from '../is_error_embeddable'; -import { CommonLegacyEmbeddable } from './legacy_embeddable_to_api'; -import { IContainer } from '../../containers'; - -export const canLinkLegacyEmbeddable = async (embeddable: CommonLegacyEmbeddable) => { - // linking and unlinking legacy embeddables is only supported on Dashboard - if ( - isErrorEmbeddable(embeddable) || - !(embeddable.getRoot() && embeddable.getRoot().isContainer) || - !isReferenceOrValueEmbeddable(embeddable) - ) { - return false; - } - - const { visualize } = core.application.capabilities; - const canSave = visualize.save; - - const { isOfAggregateQueryType } = await import('@kbn/es-query'); - const query = isFilterableEmbeddable(embeddable) && embeddable.getQuery(); - - // Textbased panels (i.e. ES|QL) should not save to library - const isTextBasedEmbeddable = isOfAggregateQueryType(query as AggregateQuery); - - return Boolean( - canSave && - isReferenceOrValueEmbeddable(embeddable) && - !embeddable.inputIsRefType(embeddable.getInput()) && - !isTextBasedEmbeddable - ); -}; - -export const linkLegacyEmbeddable = async (embeddable: CommonLegacyEmbeddable) => { - const root = embeddable.getRoot() as IContainer; - if (!isReferenceOrValueEmbeddable(embeddable) || !apiIsPresentationContainer(root)) { - throw new IncompatibleActionError(); - } - - // Link to library - const newInput = await embeddable.getInputAsRefType(); - embeddable.updateInput(newInput); - - // Replace panel in parent. - const panelToReplace = root.getInput().panels[embeddable.id]; - if (!panelToReplace) { - throw new PanelNotFoundError(); - } - await root.replacePanel(panelToReplace.explicitInput.id, { - panelType: embeddable.type, - initialState: { ...newInput }, - }); -}; diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.test.ts b/src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.test.ts deleted file mode 100644 index 50c44f2c1b253..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.test.ts +++ /dev/null @@ -1,141 +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 { ErrorEmbeddable, IContainer, PanelState, SavedObjectEmbeddableInput } from '../..'; -import { embeddablePluginMock } from '../../../mocks'; -import { createHelloWorldContainerAndEmbeddable } from '../../../tests/helpers'; -import { ReferenceOrValueEmbeddable } from '../../reference_or_value_embeddable'; -import { - ContactCardEmbeddable, - ContactCardEmbeddableFactory, - ContactCardEmbeddableInput, -} from '../../test_samples'; -import { ViewMode } from '../../types'; -import { CommonLegacyEmbeddable } from './legacy_embeddable_to_api'; -import { canLinkLegacyEmbeddable } from './link_legacy_embeddable'; -import { canUnlinkLegacyEmbeddable, unlinkLegacyEmbeddable } from './unlink_legacy_embeddable'; - -let container: IContainer; -let embeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable; - -const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); - -beforeEach(async () => { - const result = await createHelloWorldContainerAndEmbeddable(); - container = result.container; - embeddable = embeddablePluginMock.mockRefOrValEmbeddable< - ContactCardEmbeddable, - ContactCardEmbeddableInput - >(result.embeddable, { - mockedByReferenceInput: { savedObjectId: 'testSavedObjectId', id: result.embeddable.id }, - mockedByValueInput: { firstName: 'Kibanana', id: result.embeddable.id }, - }); - embeddable.updateInput({ viewMode: ViewMode.EDIT }); -}); - -test('Can unlink returns false when given an Error Embeddable', async () => { - const errorEmbeddable = new ErrorEmbeddable( - 'Wow what an awful error', - { id: ' 404' }, - embeddable.getRoot() as IContainer - ); - expect( - await canUnlinkLegacyEmbeddable(errorEmbeddable as unknown as CommonLegacyEmbeddable) - ).toBe(false); -}); - -test('Can unlink returns true when embeddable on dashboard has reference type input', async () => { - embeddable.updateInput(await embeddable.getInputAsRefType()); - expect(await canUnlinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - true - ); -}); - -test('Can unlink returns false when embeddable input is by value', async () => { - embeddable.updateInput(await embeddable.getInputAsValueType()); - expect(await canUnlinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Can unlink returns false when view mode is set to view', async () => { - embeddable.updateInput(await embeddable.getInputAsRefType()); - embeddable.updateInput({ viewMode: ViewMode.VIEW }); - expect(await canUnlinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Can unlink returns false when embeddable is not in a dashboard container', async () => { - let orphanContactCard = await embeddableFactory.create({ - id: 'orphanContact', - firstName: 'Orphan', - }); - - orphanContactCard = embeddablePluginMock.mockRefOrValEmbeddable< - ContactCardEmbeddable, - ContactCardEmbeddableInput - >(orphanContactCard, { - mockedByReferenceInput: { savedObjectId: 'test', id: orphanContactCard.id }, - mockedByValueInput: { firstName: 'Kibanana', id: orphanContactCard.id }, - }); - expect( - await canLinkLegacyEmbeddable(orphanContactCard as unknown as CommonLegacyEmbeddable) - ).toBe(false); - expect(await canUnlinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable)).toBe( - false - ); -}); - -test('Unlink replaces embeddableId and retains panel count', async () => { - const dashboard = embeddable.getRoot() as IContainer; - const originalPanelCount = Object.keys(dashboard.getInput().panels).length; - const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); - await unlinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable); - expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount); - - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - expect(newPanelId).toBeDefined(); - const newPanel = container.getInput().panels[newPanelId!]; - expect(newPanel.type).toEqual(embeddable.type); -}); - -test('Unlink unwraps all attributes from savedObject', async () => { - const complicatedAttributes = { - attribute1: 'The best attribute', - attribute2: 22, - attribute3: ['array', 'of', 'strings'], - attribute4: { nestedattribute: 'hello from the nest' }, - }; - - embeddable = embeddablePluginMock.mockRefOrValEmbeddable< - ContactCardEmbeddable, - { attributes: unknown; id: string }, - SavedObjectEmbeddableInput - >(embeddable, { - mockedByReferenceInput: { savedObjectId: 'testSavedObjectId', id: embeddable.id }, - mockedByValueInput: { attributes: complicatedAttributes, id: embeddable.id }, - }); - const dashboard = embeddable.getRoot() as IContainer; - const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); - await unlinkLegacyEmbeddable(embeddable as unknown as CommonLegacyEmbeddable); - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - expect(newPanelId).toBeDefined(); - const newPanel = container.getInput().panels[newPanelId!] as PanelState & { - explicitInput: { attributes: unknown }; - }; - expect(newPanel.type).toEqual(embeddable.type); - expect((newPanel.explicitInput as { attributes: unknown }).attributes).toEqual( - complicatedAttributes - ); -}); diff --git a/src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.ts deleted file mode 100644 index f4d0a3e0ac08a..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/compatibility/unlink_legacy_embeddable.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 { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { apiIsPresentationContainer } from '@kbn/presentation-containers'; -import { IContainer, PanelState } from '../../containers'; -import { PanelNotFoundError } from '../../errors'; -import { isReferenceOrValueEmbeddable } from '../../reference_or_value_embeddable'; -import { ViewMode } from '../../types'; -import { isErrorEmbeddable } from '../is_error_embeddable'; -import { EmbeddableInput } from '../i_embeddable'; -import { CommonLegacyEmbeddable } from './legacy_embeddable_to_api'; - -export const canUnlinkLegacyEmbeddable = async (embeddable: CommonLegacyEmbeddable) => { - return Boolean( - isReferenceOrValueEmbeddable(embeddable) && - !isErrorEmbeddable(embeddable) && - embeddable.getInput()?.viewMode !== ViewMode.VIEW && - embeddable.getRoot() && - embeddable.getRoot().isContainer && - embeddable.inputIsRefType(embeddable.getInput()) - ); -}; - -export const unlinkLegacyEmbeddable = async (embeddable: CommonLegacyEmbeddable) => { - const root = embeddable.getRoot() as IContainer; - if (!isReferenceOrValueEmbeddable(embeddable) || !apiIsPresentationContainer(root)) { - throw new IncompatibleActionError(); - } - - // unlink and update input. - const newInput = await embeddable.getInputAsValueType(); - embeddable.updateInput(newInput); - - // replace panel in parent. - const panelToReplace = root.getInput().panels[embeddable.id] as PanelState; - if (!panelToReplace) { - throw new PanelNotFoundError(); - } - await root.replacePanel(panelToReplace.explicitInput.id, { - panelType: embeddable.type, - initialState: { ...newInput, title: embeddable.getTitle() }, - }); -}; diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx deleted file mode 100644 index 84160c9b391aa..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx +++ /dev/null @@ -1,163 +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". - */ - -/* eslint-disable max-classes-per-file */ - -import { skip, take } from 'rxjs'; -import { Embeddable } from './embeddable'; -import { EmbeddableOutput, EmbeddableInput } from './i_embeddable'; -import { ViewMode } from '../types'; -import { ContactCardEmbeddable } from '../test_samples/embeddables/contact_card/contact_card_embeddable'; -import { - MockFilter, - FilterableEmbeddable, -} from '../test_samples/embeddables/filterable_embeddable'; - -class TestClass { - constructor() {} -} - -interface Output extends EmbeddableOutput { - testClass: TestClass; - inputUpdatedTimes: number; -} - -class OutputTestEmbeddable extends Embeddable { - public readonly type = 'test'; - constructor() { - super( - { id: 'test', viewMode: ViewMode.VIEW }, - { testClass: new TestClass(), inputUpdatedTimes: 0 } - ); - - this.getInput$().subscribe(() => { - this.updateOutput({ inputUpdatedTimes: this.getOutput().inputUpdatedTimes + 1 }); - }); - } - - reload() {} -} - -class PhaseTestEmbeddable extends Embeddable { - public readonly type = 'phaseTest'; - constructor() { - super({ id: 'phaseTest', viewMode: ViewMode.VIEW }, {}); - } - public reportsEmbeddableLoad(): boolean { - return true; - } - reload() {} -} - -test('Embeddable calls input subscribers when changed', (done) => { - const hello = new ContactCardEmbeddable( - { id: '123', firstName: 'Brienne', lastName: 'Tarth' }, - { execAction: (() => null) as any } - ); - - const subscription = hello - .getInput$() - .pipe(skip(1)) - .subscribe((input) => { - expect(input.nameTitle).toEqual('Sir'); - done(); - subscription.unsubscribe(); - }); - - hello.updateInput({ nameTitle: 'Sir' }); -}); - -test('Embeddable reload is called if lastReloadRequest input time changes', async () => { - const hello = new FilterableEmbeddable({ id: '123', filters: [], lastReloadRequestTime: 0 }); - - hello.reload = jest.fn(); - - hello.updateInput({ lastReloadRequestTime: 1 }); - - expect(hello.reload).toBeCalledTimes(1); -}); - -test('Embeddable reload is called if lastReloadRequest input time changed and new input is used', async () => { - const hello = new FilterableEmbeddable({ id: '123', filters: [], lastReloadRequestTime: 0 }); - - const aFilter = {} as unknown as MockFilter; - hello.reload = jest.fn(() => { - // when reload is called embeddable already has new input - expect(hello.getInput().filters).toEqual([aFilter]); - }); - - hello.updateInput({ lastReloadRequestTime: 1, filters: [aFilter] }); - - expect(hello.reload).toBeCalledTimes(1); -}); - -test('Embeddable reload is not called if lastReloadRequest input time does not change', async () => { - const hello = new FilterableEmbeddable({ id: '123', filters: [], lastReloadRequestTime: 1 }); - - hello.reload = jest.fn(); - - hello.updateInput({ lastReloadRequestTime: 1 }); - - expect(hello.reload).toBeCalledTimes(0); -}); - -test('updating output state retains instance information', async () => { - const outputTest = new OutputTestEmbeddable(); - expect(outputTest.getOutput().testClass).toBeInstanceOf(TestClass); - expect(outputTest.getOutput().inputUpdatedTimes).toBe(1); - outputTest.updateInput({ viewMode: ViewMode.EDIT }); - expect(outputTest.getOutput().inputUpdatedTimes).toBe(2); - expect(outputTest.getOutput().testClass).toBeInstanceOf(TestClass); -}); - -test('fires phase events when output changes', async () => { - const phaseEventTest = new PhaseTestEmbeddable(); - let phaseEventCount = 0; - phaseEventTest.phase$.subscribe((event) => { - if (event) { - phaseEventCount++; - } - }); - expect(phaseEventCount).toBe(1); // loading is true by default which fires an event. - phaseEventTest.updateOutput({ loading: false }); - expect(phaseEventCount).toBe(2); - phaseEventTest.updateOutput({ rendered: true }); - expect(phaseEventCount).toBe(3); -}); - -test('updated$ called after reload and batches input/output changes', async () => { - const hello = new ContactCardEmbeddable( - { id: '123', firstName: 'Brienne', lastName: 'Tarth' }, - { execAction: (() => null) as any } - ); - - const reloadSpy = jest.spyOn(hello, 'reload'); - - const input$ = hello.getInput$().pipe(skip(1)); - let inputEmittedTimes = 0; - input$.subscribe(() => { - inputEmittedTimes++; - }); - - const updated$ = hello.getUpdated$(); - let updatedEmittedTimes = 0; - updated$.subscribe(() => { - updatedEmittedTimes++; - }); - const updatedPromise = updated$.pipe(take(1)).toPromise(); - - hello.updateInput({ nameTitle: 'Sir', lastReloadRequestTime: Date.now() }); - expect(reloadSpy).toHaveBeenCalledTimes(1); - expect(inputEmittedTimes).toBe(1); - expect(updatedEmittedTimes).toBe(0); - - await updatedPromise; - - expect(updatedEmittedTimes).toBe(1); -}); diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx deleted file mode 100644 index 2f725881a6a4b..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx +++ /dev/null @@ -1,91 +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 React from 'react'; -import { EuiCard, EuiFlexItem, EuiFlexGroup, EuiFormRow } from '@elastic/eui'; - -import { Subscription } from 'rxjs'; -import { EuiButton } from '@elastic/eui'; -import * as Rx from 'rxjs'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { ContactCardEmbeddable, CONTACT_USER_TRIGGER } from './contact_card_embeddable'; - -interface Props { - embeddable: ContactCardEmbeddable; - execTrigger: UiActionsStart['executeTriggerActions']; -} - -interface State { - fullName: string; - firstName: string; -} - -export class ContactCardEmbeddableComponent extends React.Component { - private subscription?: Subscription; - private mounted: boolean = false; - - constructor(props: Props) { - super(props); - this.state = { - fullName: this.props.embeddable.getOutput().fullName, - firstName: this.props.embeddable.getInput().firstName, - }; - } - - componentDidMount() { - this.mounted = true; - this.subscription = Rx.merge( - this.props.embeddable.getOutput$(), - this.props.embeddable.getInput$() - ).subscribe(() => { - if (this.mounted) { - this.setState({ - fullName: this.props.embeddable.getOutput().fullName, - firstName: this.props.embeddable.getInput().firstName, - }); - } - }); - } - - componentWillUnmount() { - if (this.subscription) { - this.subscription.unsubscribe(); - } - this.mounted = false; - } - - emitContactTrigger = () => { - this.props.execTrigger(CONTACT_USER_TRIGGER, { - embeddable: this.props.embeddable, - }); - }; - - getCardFooterContent = () => ( - - - - {`Contact ${this.state.firstName}`} - - - - ); - - render() { - return ( - - ); - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx deleted file mode 100644 index bb3dff9631fb6..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx +++ /dev/null @@ -1,108 +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 React from 'react'; -import ReactDom from 'react-dom'; -import { Subscription } from 'rxjs'; -import type { ErrorLike } from '@kbn/expressions-plugin/common'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { Container } from '../../../containers'; -import { EmbeddableOutput, Embeddable, EmbeddableInput } from '../../../embeddables'; -import { CONTACT_CARD_EMBEDDABLE } from './contact_card_embeddable_factory'; -import { ContactCardEmbeddableComponent } from './contact_card'; - -export interface ContactCardEmbeddableInput extends EmbeddableInput { - firstName: string; - lastName?: string; - nameTitle?: string; -} - -export interface ContactCardEmbeddableOutput extends EmbeddableOutput { - fullName: string; - originalLastName?: string; -} - -export interface ContactCardEmbeddableOptions { - execAction: UiActionsStart['executeTriggerActions']; - outputOverrides?: Partial; -} - -function getFullName(input: ContactCardEmbeddableInput) { - const { nameTitle, firstName, lastName } = input; - const nameParts = [nameTitle, firstName, lastName].filter((name) => name !== undefined); - return nameParts.join(' '); -} - -export class ContactCardEmbeddable extends Embeddable< - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput -> { - private subscription: Subscription; - private node?: Element; - public readonly type: string = CONTACT_CARD_EMBEDDABLE; - - constructor( - initialInput: ContactCardEmbeddableInput, - protected readonly options: ContactCardEmbeddableOptions, - parent?: Container - ) { - super( - initialInput, - { - fullName: getFullName(initialInput), - originalLastName: initialInput.lastName, - defaultTitle: `Hello ${getFullName(initialInput)}`, - ...options.outputOverrides, - }, - parent - ); - - this.subscription = this.getInput$().subscribe(() => { - const fullName = getFullName(this.input); - this.updateOutput({ - fullName, - defaultTitle: `Hello ${fullName}`, - }); - }); - } - - public render(node: HTMLElement) { - this.node = node; - ReactDom.render( - , - node - ); - } - - public catchError?(error: ErrorLike, node: HTMLElement) { - ReactDom.render(
{error.message}
, node); - - return () => ReactDom.unmountComponentAtNode(node); - } - - public destroy() { - super.destroy(); - this.subscription.unsubscribe(); - if (this.node) { - ReactDom.unmountComponentAtNode(this.node); - } - } - - public reload() {} - - public triggerError(error: ErrorLike, fatal = false) { - if (fatal) { - this.onFatalError(error); - } else { - this.updateOutput({ error }); - } - } -} - -export const CONTACT_USER_TRIGGER = 'CONTACT_USER_TRIGGER'; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx deleted file mode 100644 index 79e0824b0275f..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 React from 'react'; -import { i18n } from '@kbn/i18n'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -import { CoreStart } from '@kbn/core/public'; -import { toMountPoint } from '@kbn/react-kibana-mount'; -import { EmbeddableFactoryDefinition } from '../../../embeddables'; -import { Container } from '../../../containers'; -import { ContactCardEmbeddable, ContactCardEmbeddableInput } from './contact_card_embeddable'; -import { ContactCardInitializer } from './contact_card_initializer'; - -export const CONTACT_CARD_EMBEDDABLE = 'CONTACT_CARD_EMBEDDABLE'; - -export class ContactCardEmbeddableFactory - implements EmbeddableFactoryDefinition -{ - public readonly type = CONTACT_CARD_EMBEDDABLE; - savedObjectMetaData = { - name: 'Contact card', - type: CONTACT_CARD_EMBEDDABLE, - getIconForSavedObject: () => 'document', - }; - - constructor( - protected readonly execTrigger: UiActionsStart['executeTriggerActions'], - private readonly core: CoreStart - ) {} - - public async isEditable() { - return true; - } - - public getDisplayName() { - return i18n.translate('embeddableApi.samples.contactCard.displayName', { - defaultMessage: 'contact card', - }); - } - - public getDefaultInput() { - return {}; - } - - public getExplicitInput = (): Promise> => { - return new Promise((resolve) => { - const modalSession = this.core.overlays.openModal( - toMountPoint( - { - modalSession.close(); - // @ts-expect-error - resolve(undefined); - }} - onCreate={(input: { firstName: string; lastName?: string }) => { - modalSession.close(); - resolve(input); - }} - />, - this.core - ), - { - 'data-test-subj': 'createContactCardEmbeddable', - } - ); - }); - }; - - public create = async (initialInput: ContactCardEmbeddableInput, parent?: Container) => { - return new ContactCardEmbeddable( - initialInput, - { - execAction: this.execTrigger, - }, - parent - ); - }; -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx deleted file mode 100644 index e2cc363b6ec3a..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx +++ /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 React from 'react'; -import { ContactCardEmbeddableComponent } from './contact_card'; -import { ContactCardEmbeddable } from './contact_card_embeddable'; - -export class ContactCardEmbeddableReact extends ContactCardEmbeddable { - public render() { - return ( - - ); - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.ts deleted file mode 100644 index 28e651cd14d02..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 { Container } from '../../../containers'; -import { ContactCardEmbeddableInput } from './contact_card_embeddable'; -import { ContactCardEmbeddableFactory } from './contact_card_embeddable_factory'; -import { ContactCardEmbeddableReact } from './contact_card_embeddable_react'; - -export const CONTACT_CARD_EMBEDDABLE_REACT = 'CONTACT_CARD_EMBEDDABLE_REACT'; - -export class ContactCardEmbeddableReactFactory extends ContactCardEmbeddableFactory { - public readonly type = CONTACT_CARD_EMBEDDABLE_REACT as ContactCardEmbeddableFactory['type']; - - public create = async (initialInput: ContactCardEmbeddableInput, parent?: Container) => { - return new ContactCardEmbeddableReact( - initialInput, - { - execAction: this.execTrigger, - }, - parent - ); - }; -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx deleted file mode 100644 index eaeeb592d9eb3..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx +++ /dev/null @@ -1,37 +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 { ContactCardEmbeddable } from './contact_card_embeddable'; - -export class ContactCardExportableEmbeddable extends ContactCardEmbeddable { - public getInspectorAdapters = () => { - return { - tables: { - allowCsvExport: true, - tables: { - layer1: { - type: 'datatable', - columns: [ - { id: 'firstName', name: 'First Name' }, - { id: 'originalLastName', name: 'Last Name' }, - ], - rows: [ - { - firstName: this.getInput().firstName, - orignialLastName: this.getInput().lastName, - }, - ], - }, - }, - }, - }; - }; -} - -export const CONTACT_EXPORTABLE_USER_TRIGGER = 'CONTACT_EXPORTABLE_USER_TRIGGER'; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable_factory.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable_factory.tsx deleted file mode 100644 index 7ddf5f1711b61..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable_factory.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 React from 'react'; -import { i18n } from '@kbn/i18n'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -import { CoreStart } from '@kbn/core/public'; -import { toMountPoint } from '@kbn/react-kibana-mount'; -import { EmbeddableFactoryDefinition } from '../../../embeddables'; -import { Container } from '../../../containers'; -import { ContactCardEmbeddableInput } from './contact_card_embeddable'; -import { ContactCardExportableEmbeddable } from './contact_card_exportable_embeddable'; -import { ContactCardInitializer } from './contact_card_initializer'; - -export const CONTACT_CARD_EXPORTABLE_EMBEDDABLE = 'CONTACT_CARD_EXPORTABLE_EMBEDDABLE'; - -export class ContactCardExportableEmbeddableFactory - implements EmbeddableFactoryDefinition -{ - public readonly type = CONTACT_CARD_EXPORTABLE_EMBEDDABLE; - - constructor( - private readonly execTrigger: UiActionsStart['executeTriggerActions'], - private readonly core: CoreStart - ) {} - - public async isEditable() { - return true; - } - - public getDefaultInput() { - return {}; - } - - public getDisplayName() { - return i18n.translate('embeddableApi.samples.contactCard.displayName', { - defaultMessage: 'contact card', - }); - } - - public getExplicitInput = (): Promise> => { - return new Promise((resolve) => { - const modalSession = this.core.overlays.openModal( - toMountPoint( - { - modalSession.close(); - // @ts-expect-error - resolve(undefined); - }} - onCreate={(input: { firstName: string; lastName?: string }) => { - modalSession.close(); - resolve(input); - }} - />, - this.core - ), - { - 'data-test-subj': 'createContactCardEmbeddable', - } - ); - }); - }; - - public create = async (initialInput: ContactCardEmbeddableInput, parent?: Container) => { - return new ContactCardExportableEmbeddable( - initialInput, - { - execAction: this.execTrigger, - }, - parent - ); - }; -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_initializer.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_initializer.tsx deleted file mode 100644 index 10c07ef5d5aad..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_initializer.tsx +++ /dev/null @@ -1,88 +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 { - EuiForm, - EuiFormRow, - EuiFieldText, - EuiModalHeader, - EuiModalHeaderTitle, - EuiModalBody, - EuiButton, - EuiModalFooter, - EuiButtonEmpty, -} from '@elastic/eui'; -import React, { Component } from 'react'; - -export interface ContactCardInitializerProps { - onCreate: (name: { lastName?: string; firstName: string }) => void; - onCancel: () => void; -} - -interface State { - firstName?: string; - lastName?: string; -} - -export class ContactCardInitializer extends Component { - constructor(props: ContactCardInitializerProps) { - super(props); - this.state = {}; - } - - render() { - return ( -
- - Create a new greeting card - - - - - - this.setState({ firstName: e.target.value })} - /> - - - - this.setState({ lastName: e.target.value })} - /> - - - - - - Cancel - - { - if (this.state.firstName) { - this.props.onCreate({ - firstName: this.state.firstName, - ...(this.state.lastName ? { lastName: this.state.lastName } : {}), - }); - } - }} - fill - > - Create - - -
- ); - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/descriptive_contact_card_embeddable_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/descriptive_contact_card_embeddable_factory.ts deleted file mode 100644 index fa251fc7cdb04..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/descriptive_contact_card_embeddable_factory.ts +++ /dev/null @@ -1,44 +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 { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -import { Container, EmbeddableFactoryDefinition } from '../../..'; -import { ContactCardEmbeddable, ContactCardEmbeddableInput } from './contact_card_embeddable'; - -export const DESCRIPTIVE_CONTACT_CARD_EMBEDDABLE = 'DESCRIPTIVE_CONTACT_CARD_EMBEDDABLE'; - -export class DescriptiveContactCardEmbeddableFactory - implements EmbeddableFactoryDefinition -{ - public readonly type = DESCRIPTIVE_CONTACT_CARD_EMBEDDABLE; - - constructor(protected readonly execTrigger: UiActionsStart['executeTriggerActions']) {} - - public async isEditable() { - return true; - } - - public getDisplayName() { - return 'descriptive contact card'; - } - - public create = async (initialInput: ContactCardEmbeddableInput, parent?: Container) => { - return new ContactCardEmbeddable( - initialInput, - { - execAction: this.execTrigger, - outputOverrides: { - defaultDescription: 'This is a family friend', - }, - }, - parent - ); - }; -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts deleted file mode 100644 index 5344e74647c2f..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.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 * from './contact_card'; -export * from './contact_card_embeddable'; -export * from './contact_card_embeddable_factory'; -export * from './contact_card_exportable_embeddable'; -export * from './contact_card_exportable_embeddable_factory'; -export * from './contact_card_embeddable_react'; -export * from './contact_card_embeddable_react_factory'; -export * from './contact_card_initializer'; -export * from './slow_contact_card_embeddable_factory'; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory.ts deleted file mode 100644 index aeb8714332521..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { Container, EmbeddableFactoryDefinition } from '../../..'; -import { ContactCardEmbeddable, ContactCardEmbeddableInput } from './contact_card_embeddable'; -import { CONTACT_CARD_EMBEDDABLE } from './contact_card_embeddable_factory'; - -interface SlowContactCardEmbeddableFactoryOptions { - execAction: UiActionsStart['executeTriggerActions']; - loadTickCount?: number; -} - -export class SlowContactCardEmbeddableFactory - implements EmbeddableFactoryDefinition -{ - private loadTickCount = 0; - public readonly type = CONTACT_CARD_EMBEDDABLE; - - constructor(private readonly options: SlowContactCardEmbeddableFactoryOptions) { - if (options.loadTickCount) { - this.loadTickCount = options.loadTickCount; - } - } - - public async isEditable() { - return true; - } - - public getDisplayName() { - return 'slow to load contact card'; - } - - public create = async (initialInput: ContactCardEmbeddableInput, parent?: Container) => { - for (let i = 0; i < this.loadTickCount; i++) { - await Promise.resolve(); - } - return new ContactCardEmbeddable(initialInput, { execAction: this.options.execAction }, parent); - }; -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/empty_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/empty_embeddable.tsx deleted file mode 100644 index f05f4f8153e8c..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/empty_embeddable.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 { Embeddable, EmbeddableInput, EmbeddableOutput } from '../..'; - -export const EMPTY_EMBEDDABLE = 'EMPTY_EMBEDDABLE'; - -export class EmptyEmbeddable extends Embeddable { - public readonly type = EMPTY_EMBEDDABLE; - constructor(initialInput: EmbeddableInput) { - super(initialInput, {}); - } - public render() {} - public reload() {} -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx deleted file mode 100644 index 3dc9952d6da42..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 { Container, ContainerInput } from '../../containers'; -import { EmbeddableStart } from '../../../plugin'; -import { MockFilter } from './filterable_embeddable'; - -export const FILTERABLE_CONTAINER = 'FILTERABLE_CONTAINER'; - -export interface FilterableContainerInput extends ContainerInput { - filters: MockFilter[]; -} - -/** - * interfaces are not allowed to specify a sub-set of the required types until - * https://github.com/microsoft/TypeScript/issues/15300 is fixed so we use a type - * here instead - */ -type InheritedChildrenInput = { - filters: MockFilter[]; - id?: string; -}; - -export class FilterableContainer extends Container< - InheritedChildrenInput, - FilterableContainerInput -> { - public readonly type = FILTERABLE_CONTAINER; - - constructor( - initialInput: FilterableContainerInput, - getFactory: EmbeddableStart['getEmbeddableFactory'], - parent?: Container - ) { - super(initialInput, { embeddableLoaded: {} }, getFactory, parent); - } - - public getInheritedInput() { - return { - filters: this.input.filters, - viewMode: this.input.viewMode, - }; - } - - public render() {} -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container_factory.ts deleted file mode 100644 index b394f905d3378..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container_factory.ts +++ /dev/null @@ -1,42 +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 { i18n } from '@kbn/i18n'; -import { Container, EmbeddableFactoryDefinition } from '../..'; -import { - FilterableContainer, - FilterableContainerInput, - FILTERABLE_CONTAINER, -} from './filterable_container'; -import { EmbeddableStart } from '../../../plugin'; - -export class FilterableContainerFactory - implements EmbeddableFactoryDefinition -{ - public readonly type = FILTERABLE_CONTAINER; - - constructor( - private readonly getFactory: () => Promise - ) {} - - public getDisplayName() { - return i18n.translate('embeddableApi.samples.filterableContainer.displayName', { - defaultMessage: 'filterable dashboard', - }); - } - - public async isEditable() { - return true; - } - - public create = async (initialInput: FilterableContainerInput, parent?: Container) => { - const getEmbeddableFactory = await this.getFactory(); - return new FilterableContainer(initialInput, getEmbeddableFactory, parent); - }; -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx deleted file mode 100644 index ee32fa6e2642f..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx +++ /dev/null @@ -1,42 +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 { IContainer } from '../../containers'; -import { EmbeddableOutput, EmbeddableInput, Embeddable } from '../../embeddables'; - -/** @internal */ -export interface MockFilter { - $state?: {}; - meta: {}; - query?: {}; -} - -export const FILTERABLE_EMBEDDABLE = 'FILTERABLE_EMBEDDABLE'; - -export interface FilterableEmbeddableInput extends EmbeddableInput { - filters: MockFilter[]; -} - -export class FilterableEmbeddable extends Embeddable { - public readonly type = FILTERABLE_EMBEDDABLE; - constructor(initialInput: FilterableEmbeddableInput, parent?: IContainer) { - super(initialInput, {}, parent); - } - - public getInspectorAdapters(): Record { - const inspectorAdapters: Record = { - filters: `My filters are ${JSON.stringify(this.input.filters)}`, - }; - return inspectorAdapters; - } - - public render() {} - - public reload() {} -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable_factory.ts deleted file mode 100644 index cba773effb9ed..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable_factory.ts +++ /dev/null @@ -1,37 +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 { i18n } from '@kbn/i18n'; -import { - FilterableEmbeddable, - FilterableEmbeddableInput, - FILTERABLE_EMBEDDABLE, -} from './filterable_embeddable'; -import { EmbeddableFactoryDefinition } from '../../embeddables'; -import { IContainer } from '../../containers'; - -export class FilterableEmbeddableFactory - implements EmbeddableFactoryDefinition -{ - public readonly type = FILTERABLE_EMBEDDABLE; - - public async isEditable() { - return true; - } - - public getDisplayName() { - return i18n.translate('embeddableApi.samples.filterableEmbeddable.displayName', { - defaultMessage: 'filterable', - }); - } - - public async create(initialInput: FilterableEmbeddableInput, parent?: IContainer) { - return new FilterableEmbeddable(initialInput, parent); - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx deleted file mode 100644 index fe772a1f9a007..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 React from 'react'; -import ReactDOM from 'react-dom'; -import { I18nProvider } from '@kbn/i18n-react'; -import { Container, ViewMode, ContainerInput } from '../..'; -import { HelloWorldContainerComponent } from './hello_world_container_component'; -import { EmbeddableStart } from '../../../plugin'; -import { EmbeddableContainerSettings } from '../../containers/i_container'; - -export const HELLO_WORLD_CONTAINER = 'HELLO_WORLD_CONTAINER'; - -/** - * interfaces are not allowed to specify a sub-set of the required types until - * https://github.com/microsoft/TypeScript/issues/15300 is fixed so we use a type - * here instead - */ -type InheritedInput = { - id: string; - viewMode: ViewMode; - lastName: string; -}; - -interface HelloWorldContainerInput extends ContainerInput { - lastName?: string; -} - -interface HelloWorldContainerOptions { - getEmbeddableFactory?: EmbeddableStart['getEmbeddableFactory']; -} - -export class HelloWorldContainer extends Container { - public readonly type = HELLO_WORLD_CONTAINER; - - constructor( - input: ContainerInput<{ firstName: string; lastName: string }>, - options: HelloWorldContainerOptions, - initializeSettings?: EmbeddableContainerSettings - ) { - super( - input, - { embeddableLoaded: {} }, - options.getEmbeddableFactory || (() => undefined), - undefined, - initializeSettings - ); - } - - public getInheritedInput(id: string) { - return { - id, - viewMode: this.input.viewMode || ViewMode.EDIT, - lastName: this.input.lastName || 'foo', - }; - } - - public render(node: HTMLElement) { - ReactDOM.render( - - - , - node - ); - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx deleted file mode 100644 index 7bc322c3a1dde..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx +++ /dev/null @@ -1,100 +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 React, { Component, RefObject } from 'react'; -import { Subscription } from 'rxjs'; - -import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; - -import { IContainer, PanelState } from '../..'; -import { EmbeddablePanel } from '../../../embeddable_panel'; - -interface Props { - container: IContainer; -} - -interface State { - panels: { [key: string]: PanelState }; - loaded: { [key: string]: boolean }; -} - -export class HelloWorldContainerComponent extends Component { - private roots: { [key: string]: RefObject } = {}; - private mounted: boolean = false; - private inputSubscription?: Subscription; - private outputSubscription?: Subscription; - - constructor(props: Props) { - super(props); - - Object.values(this.props.container.getInput().panels).forEach((panelState) => { - this.roots[panelState.explicitInput.id] = React.createRef(); - }); - - this.state = { - loaded: this.props.container.getOutput().embeddableLoaded, - panels: this.props.container.getInput().panels, - }; - } - - public async componentDidMount() { - this.mounted = true; - - this.inputSubscription = this.props.container.getInput$().subscribe(() => { - if (this.mounted) { - this.setState({ panels: this.props.container.getInput().panels }); - } - }); - - this.outputSubscription = this.props.container.getOutput$().subscribe(() => { - if (this.mounted) { - this.setState({ loaded: this.props.container.getOutput().embeddableLoaded }); - } - }); - } - - public componentWillUnmount() { - this.mounted = false; - this.props.container.destroy(); - - if (this.inputSubscription) { - this.inputSubscription.unsubscribe(); - } - - if (this.outputSubscription) { - this.outputSubscription.unsubscribe(); - } - } - - public render() { - return ( -
-

HELLO WORLD! These are my precious embeddable children:

- - {this.renderList()} -
- ); - } - - private renderList() { - const list = Object.values(this.state.panels).map((panelState) => { - const item = ( - - - this.props.container.untilEmbeddableLoaded(panelState.explicitInput.id) - } - /> - - ); - return item; - }); - return list; - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/index.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/index.ts deleted file mode 100644 index 97f6d31622283..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/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". - */ - -export * from './contact_card'; -export * from './empty_embeddable'; -export * from './filterable_container'; -export * from './filterable_container_factory'; -export * from './filterable_embeddable'; -export * from './filterable_embeddable_factory'; -export * from './hello_world_container'; -export * from './hello_world_container_component'; -export * from './time_range_container'; -export * from './time_range_embeddable_factory'; -export * from './time_range_embeddable'; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_container.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_container.ts deleted file mode 100644 index a7d306c86ed8c..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_container.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 type { TimeRange } from '@kbn/es-query'; -import { ContainerInput, Container, ContainerOutput, EmbeddableStart } from '../../..'; - -/** - * interfaces are not allowed to specify a sub-set of the required types until - * https://github.com/microsoft/TypeScript/issues/15300 is fixed so we use a type - * here instead - */ -type InheritedChildrenInput = { - timeRange: TimeRange; - id?: string; -}; - -interface ContainerTimeRangeInput extends ContainerInput { - timeRange: TimeRange; -} - -const TIME_RANGE_CONTAINER = 'TIME_RANGE_CONTAINER'; - -export class TimeRangeContainer extends Container< - InheritedChildrenInput, - ContainerTimeRangeInput, - ContainerOutput -> { - public readonly type = TIME_RANGE_CONTAINER; - constructor( - initialInput: ContainerTimeRangeInput, - getFactory: EmbeddableStart['getEmbeddableFactory'], - parent?: Container - ) { - super(initialInput, { embeddableLoaded: {} }, getFactory, parent); - } - - public getAllDataViews() { - return []; - } - - public getInheritedInput() { - return { timeRange: this.input.timeRange }; - } - - public render() {} - - public reload() {} -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable.ts deleted file mode 100644 index fa9dca4071bbb..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable.ts +++ /dev/null @@ -1,37 +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 type { TimeRange } from '@kbn/es-query'; -import { EmbeddableOutput, Embeddable, EmbeddableInput, IContainer } from '../../..'; - -export interface EmbeddableTimeRangeInput extends EmbeddableInput { - timeRange: TimeRange; -} - -export const TIME_RANGE_EMBEDDABLE = 'TIME_RANGE_EMBEDDABLE'; - -export class TimeRangeEmbeddable extends Embeddable { - public readonly type = TIME_RANGE_EMBEDDABLE; - - constructor(initialInput: EmbeddableTimeRangeInput, parent?: IContainer) { - const { title: defaultTitle, description: defaultDescription } = initialInput; - super( - initialInput, - { - defaultTitle, - defaultDescription, - }, - parent - ); - } - - public render() {} - - public reload() {} -} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable_factory.ts deleted file mode 100644 index fefbfd5df95d1..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/time_range_embeddable_factory.ts +++ /dev/null @@ -1,33 +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 { IContainer, EmbeddableFactoryDefinition } from '../../..'; -import { - TIME_RANGE_EMBEDDABLE, - TimeRangeEmbeddable, - EmbeddableTimeRangeInput, -} from './time_range_embeddable'; - -export class TimeRangeEmbeddableFactory - implements EmbeddableFactoryDefinition -{ - public readonly type = TIME_RANGE_EMBEDDABLE; - - public async isEditable() { - return true; - } - - public async create(initialInput: EmbeddableTimeRangeInput, parent?: IContainer) { - return new TimeRangeEmbeddable(initialInput, parent); - } - - public getDisplayName() { - return 'time range'; - } -} diff --git a/src/plugins/embeddable/public/lib/test_samples/index.ts b/src/plugins/embeddable/public/lib/test_samples/index.ts deleted file mode 100644 index b27497d8d8d23..0000000000000 --- a/src/plugins/embeddable/public/lib/test_samples/index.ts +++ /dev/null @@ -1,10 +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 * from './embeddables'; diff --git a/src/plugins/embeddable/public/tests/container.test.ts b/src/plugins/embeddable/public/tests/container.test.ts deleted file mode 100644 index 1209f54fb8866..0000000000000 --- a/src/plugins/embeddable/public/tests/container.test.ts +++ /dev/null @@ -1,817 +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 { coreMock } from '@kbn/core/public/mocks'; -import * as Rx from 'rxjs'; -import { skip } from 'rxjs'; -import { EmbeddableOutput, isErrorEmbeddable, SavedObjectEmbeddableInput, ViewMode } from '../lib'; -import { ERROR_EMBEDDABLE_TYPE } from '../lib/embeddables/error_embeddable'; -import { - ContactCardEmbeddable, - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, -} from '../lib/test_samples/embeddables/contact_card/contact_card_embeddable'; -import { CONTACT_CARD_EMBEDDABLE } from '../lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory'; -import { SlowContactCardEmbeddableFactory } from '../lib/test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory'; -import { - FilterableContainer, - FilterableContainerInput, -} from '../lib/test_samples/embeddables/filterable_container'; -import { - FilterableEmbeddable, - FilterableEmbeddableInput, - FILTERABLE_EMBEDDABLE, - MockFilter, -} from '../lib/test_samples/embeddables/filterable_embeddable'; -import { HelloWorldContainer } from '../lib/test_samples/embeddables/hello_world_container'; -import { HelloWorldEmbeddableFactoryDefinition, HELLO_WORLD_EMBEDDABLE } from './fixtures'; -import { createHelloWorldContainerAndEmbeddable, of } from './helpers'; -import { testPlugin } from './test_plugin'; - -describe('container initialization', () => { - const panels = { - '123': { - explicitInput: { id: '123' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - '456': { - explicitInput: { id: '456' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - '789': { - explicitInput: { id: '789' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - }; - - const expectEmbeddableLoaded = (container: HelloWorldContainer, id: string) => { - expect(container.getOutput().embeddableLoaded['123']).toBe(true); - const embeddable = container.getChild('123'); - expect(embeddable).toBeDefined(); - expect(embeddable.id).toBe('123'); - }; - - it('initializes embeddables', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels, - }); - - expectEmbeddableLoaded(container, '123'); - expectEmbeddableLoaded(container, '456'); - expectEmbeddableLoaded(container, '789'); - }); - - it('initializes embeddables once and only once with multiple input updates', async () => { - const { container, contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels, - }); - container.updateInput({ lastReloadRequestTime: 1 }); - container.updateInput({ lastReloadRequestTime: 2 }); - expect(contactCardCreateSpy).toHaveBeenCalledTimes(4); - }); - - it('initializes embeddables in order', async () => { - const childIdInitializeOrder = ['456', '123', '789']; - const { contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable( - { - id: 'hello', - panels, - }, - {}, - { childIdInitializeOrder } - ); - - await new Promise((r) => setTimeout(r, 1)); - for (const [index, orderedId] of childIdInitializeOrder.entries()) { - expect(contactCardCreateSpy).toHaveBeenNthCalledWith( - index + 1, - expect.objectContaining({ id: orderedId }), - expect.anything() // parent passed into create method - ); - } - }); - - it('initializes embeddables in order with partial order arg', async () => { - const childIdInitializeOrder = ['789', 'idontexist']; - const { contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable( - { - id: 'hello', - panels, - }, - {}, - { childIdInitializeOrder } - ); - const expectedInitializeOrder = ['789', '123', '456']; - - await new Promise((r) => setTimeout(r, 1)); - for (const [index, orderedId] of expectedInitializeOrder.entries()) { - expect(contactCardCreateSpy).toHaveBeenNthCalledWith( - index + 1, - expect.objectContaining({ id: orderedId }), - expect.anything() // parent passed into create method - ); - } - }); - - it('initializes embeddables in order, awaiting each', async () => { - const childIdInitializeOrder = ['456', '123', '789']; - const { container, contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable( - { - id: 'hello', - panels, - }, - {}, - { childIdInitializeOrder, initializeSequentially: true } - ); - - const untilEmbeddableLoadedMock = jest.spyOn(container, 'untilEmbeddableLoaded'); - - await new Promise((r) => setTimeout(r, 10)); - - for (const [index, orderedId] of childIdInitializeOrder.entries()) { - await container.untilEmbeddableLoaded(orderedId); - expect(contactCardCreateSpy).toHaveBeenNthCalledWith( - index + 1, - expect.objectContaining({ id: orderedId }), - expect.anything() // parent passed into create method - ); - expect(untilEmbeddableLoadedMock).toHaveBeenCalledWith(orderedId); - } - }); -}); - -test('Container.addNewEmbeddable', async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {} }, - { - firstName: 'Susy', - } - ); - expect(embeddable).toBeDefined(); - - if (!isErrorEmbeddable(embeddable)) { - expect(embeddable.getInput().firstName).toBe('Susy'); - } else { - expect(false).toBe(true); - } - - const embeddableInContainer = container.getChild(embeddable.id); - expect(embeddableInContainer).toBeDefined(); - expect(embeddableInContainer.id).toBe(embeddable.id); -}); - -test('Container.removeEmbeddable removes and cleans up', async () => { - const { start } = await createHelloWorldContainerAndEmbeddable(); - - const container = new HelloWorldContainer( - { - id: 'hello', - panels: { - '123': { - explicitInput: { id: '123', firstName: 'Sam', lastName: 'Tarley' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - }, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - const embeddable = await container.addNewEmbeddable< - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, - ContactCardEmbeddable - >(CONTACT_CARD_EMBEDDABLE, { - firstName: 'Susy', - lastName: 'Q', - }); - - if (isErrorEmbeddable(embeddable)) { - expect(false).toBe(true); - return; - } - - embeddable.updateInput({ lastName: 'Z' }); - - container - .getOutput$() - .pipe(skip(1)) - .subscribe(() => { - const noFind = container.getChild(embeddable.id); - expect(noFind).toBeUndefined(); - - expect(container.getInput().panels[embeddable.id]).toBeUndefined(); - if (isErrorEmbeddable(embeddable)) { - expect(false).toBe(true); - } - - expect(() => embeddable.updateInput({ nameTitle: 'Sir' })).toThrowError(); - expect(container.getOutput().embeddableLoaded[embeddable.id]).toBeUndefined(); - }); - - container.removeEmbeddable(embeddable.id); -}); - -test('Container.input$ is notified when child embeddable input is updated', async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {} }, - { - firstName: 'Susy', - lastName: 'Q', - } - ); - - expect(isErrorEmbeddable(embeddable)).toBe(false); - - const changes = jest.fn(); - - expect(changes).toHaveBeenCalledTimes(0); - - const subscription = container.getInput$().subscribe(changes); - - expect(changes).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ lastName: 'Z' }); - - expect(changes).toHaveBeenCalledTimes(2); - - expect(embeddable.getInput().lastName === 'Z'); - - embeddable.updateInput({ lastName: embeddable.getOutput().originalLastName }); - - expect(embeddable.getInput().lastName === 'Q'); - - expect(changes).toBeCalledTimes(3); - - subscription.unsubscribe(); - - embeddable.updateInput({ nameTitle: 'Dr.' }); - - expect(changes).toBeCalledTimes(3); -}); - -test('Container.input$', async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {} }, - { - firstName: 'Susy', - id: 'Susy', - } - ); - - expect(isErrorEmbeddable(embeddable)).toBe(false); - - const changes = jest.fn(); - const input = container.getInput(); - expect(input.panels[embeddable.id].explicitInput).toEqual({ firstName: 'Susy', id: 'Susy' }); - - const subscription = container.getInput$().subscribe(changes); - embeddable.updateInput({ nameTitle: 'Dr.' }); - expect(container.getInput().panels[embeddable.id].explicitInput).toEqual({ - nameTitle: 'Dr.', - firstName: 'Susy', - id: 'Susy', - }); - subscription.unsubscribe(); -}); - -test('Container.getInput$ not triggered if state is the same', async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {} }, - { - firstName: 'Susy', - id: 'Susy', - } - ); - - expect(isErrorEmbeddable(embeddable)).toBe(false); - - const changes = jest.fn(); - const input = container.getInput(); - expect(input.panels[embeddable.id].explicitInput).toEqual({ - id: 'Susy', - firstName: 'Susy', - }); - const subscription = container.getInput$().subscribe(changes); - embeddable.updateInput({ nameTitle: 'Dr.' }); - expect(changes).toBeCalledTimes(2); - embeddable.updateInput({ nameTitle: 'Dr.' }); - expect(changes).toBeCalledTimes(2); - subscription.unsubscribe(); -}); - -test('Container view mode change propagates to children', async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {}, viewMode: ViewMode.VIEW }, - { - firstName: 'Susy', - id: 'Susy', - } - ); - - expect(embeddable.getInput().viewMode).toBe(ViewMode.VIEW); - - container.updateInput({ viewMode: ViewMode.EDIT }); - - expect(embeddable.getInput().viewMode).toBe(ViewMode.EDIT); -}); - -test(`Container updates its state when a child's input is updated`, async () => { - const { container, embeddable, start } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {}, viewMode: ViewMode.VIEW }, - { - id: '123', - firstName: 'Susy', - } - ); - - expect(isErrorEmbeddable(embeddable)).toBe(false); - - const containerSubscription = Rx.merge(container.getInput$(), container.getOutput$()).subscribe( - () => { - const child = container.getChild(embeddable.id); - if ( - container.getOutput().embeddableLoaded[embeddable.id] && - child.getInput().nameTitle === 'Dr.' - ) { - containerSubscription.unsubscribe(); - - // Make sure a brand new container built off the output of container also creates an embeddable - // with "Dr.", not the default the embeddable was first added with. Makes sure changed input - // is preserved with the container. - const containerClone = new HelloWorldContainer(container.getInput(), { - getEmbeddableFactory: start.getEmbeddableFactory, - }); - const cloneSubscription = Rx.merge( - containerClone.getOutput$(), - containerClone.getInput$() - ).subscribe(() => { - const childClone = containerClone.getChild(embeddable.id); - - if ( - containerClone.getOutput().embeddableLoaded[embeddable.id] && - childClone.getInput().nameTitle === 'Dr.' - ) { - cloneSubscription.unsubscribe(); - } - }); - } - } - ); - - embeddable.updateInput({ nameTitle: 'Dr.' }); -}); - -test(`Derived container state passed to children`, async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {}, viewMode: ViewMode.VIEW }, - { - firstName: 'Susy', - } - ); - - let subscription = embeddable - .getInput$() - .pipe(skip(1)) - .subscribe((changes: Partial) => { - expect(changes.viewMode).toBe(ViewMode.EDIT); - }); - container.updateInput({ viewMode: ViewMode.EDIT }); - - subscription.unsubscribe(); - subscription = embeddable - .getInput$() - .pipe(skip(1)) - .subscribe((changes: Partial) => { - expect(changes.viewMode).toBe(ViewMode.VIEW); - }); - container.updateInput({ viewMode: ViewMode.VIEW }); - subscription.unsubscribe(); -}); - -test(`Can subscribe to children embeddable updates`, async () => { - const { embeddable } = await createHelloWorldContainerAndEmbeddable( - { - id: 'hello container', - panels: {}, - viewMode: ViewMode.VIEW, - }, - { - firstName: 'Susy', - } - ); - - expect(isErrorEmbeddable(embeddable)).toBe(false); - - const subscription = embeddable.getInput$().subscribe((input: ContactCardEmbeddableInput) => { - if (input.nameTitle === 'Dr.') { - subscription.unsubscribe(); - } - }); - embeddable.updateInput({ nameTitle: 'Dr.' }); -}); - -test('Test nested reactions', async () => { - const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( - { id: 'hello', panels: {}, viewMode: ViewMode.VIEW }, - { - firstName: 'Susy', - } - ); - - expect(isErrorEmbeddable(embeddable)).toBe(false); - - const containerSubscription = container.getInput$().subscribe((input: any) => { - const embeddableNameTitle = embeddable.getInput().nameTitle; - const viewMode = input.viewMode; - const nameTitleFromContainer = container.getInputForChild( - embeddable.id - ).nameTitle; - if ( - embeddableNameTitle === 'Dr.' && - nameTitleFromContainer === 'Dr.' && - viewMode === ViewMode.EDIT - ) { - containerSubscription.unsubscribe(); - embeddableSubscription.unsubscribe(); - } - }); - - const embeddableSubscription = embeddable.getInput$().subscribe(() => { - if (embeddable.getInput().nameTitle === 'Dr.') { - container.updateInput({ viewMode: ViewMode.EDIT }); - } - }); - - embeddable.updateInput({ nameTitle: 'Dr.' }); -}); - -test('Explicit embeddable input mapped to undefined will default to inherited', async () => { - const { start } = await createHelloWorldContainerAndEmbeddable(); - const derivedFilter: MockFilter = { - $state: { store: 'appState' }, - meta: { disabled: false, alias: 'name', negate: false }, - query: { match: {} }, - }; - const container = new FilterableContainer( - { id: 'hello', panels: {}, filters: [derivedFilter] }, - start.getEmbeddableFactory - ); - const embeddable = await container.addNewEmbeddable< - FilterableEmbeddableInput, - EmbeddableOutput, - FilterableEmbeddable - >(FILTERABLE_EMBEDDABLE, {}); - - if (isErrorEmbeddable(embeddable)) { - throw new Error('Error adding embeddable'); - } - - embeddable.updateInput({ filters: [] }); - - expect(container.getInputForChild(embeddable.id).filters).toEqual([]); - - embeddable.updateInput({ filters: undefined }); - - expect(container.getInputForChild(embeddable.id).filters).toEqual([ - derivedFilter, - ]); -}); - -test('Explicit embeddable input mapped to undefined with no inherited value will get passed to embeddable', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels: {} }); - - const embeddable = await container.addNewEmbeddable< - FilterableEmbeddableInput, - EmbeddableOutput, - FilterableEmbeddable - >(FILTERABLE_EMBEDDABLE, {}); - - if (isErrorEmbeddable(embeddable)) { - throw new Error('Error adding embeddable'); - } - - embeddable.updateInput({ filters: [] }); - - expect(container.getInputForChild(embeddable.id).filters).toEqual([]); - - const subscription = embeddable - .getInput$() - .pipe(skip(1)) - .subscribe(() => { - if (embeddable.getInput().filters === undefined) { - subscription.unsubscribe(); - } - }); - - embeddable.updateInput({ filters: undefined }); -}); - -test('Panel removed from input state', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels: {}, - }); - - const embeddable = await container.addNewEmbeddable< - FilterableEmbeddableInput, - EmbeddableOutput, - FilterableEmbeddable - >(FILTERABLE_EMBEDDABLE, {}); - - const filteredPanels = { ...container.getInput().panels }; - delete filteredPanels[embeddable.id]; - const newInput: Partial = { - ...container.getInput(), - panels: filteredPanels, - }; - - container.updateInput(newInput); - await new Promise((r) => setTimeout(r, 1)); - - expect(container.getChild(embeddable.id)).toBeUndefined(); - expect(container.getOutput().embeddableLoaded[embeddable.id]).toBeUndefined(); -}); - -test('Panel added to input state', async () => { - const { container, start } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels: {}, - }); - - const embeddable = await container.addNewEmbeddable< - FilterableEmbeddableInput, - EmbeddableOutput, - FilterableEmbeddable - >(FILTERABLE_EMBEDDABLE, {}); - - const embeddable2 = await container.addNewEmbeddable< - FilterableEmbeddableInput, - EmbeddableOutput, - FilterableEmbeddable - >(FILTERABLE_EMBEDDABLE, {}); - - const container2 = new FilterableContainer( - { id: 'hello', panels: {}, filters: [] }, - start.getEmbeddableFactory - ); - - container2.updateInput(container.getInput()); - await new Promise((r) => setTimeout(r, 1)); - - expect(container.getChild(embeddable.id)).toBeDefined(); - expect(container.getOutput().embeddableLoaded[embeddable.id]).toBe(true); - expect(container.getChild(embeddable2.id)).toBeDefined(); - expect(container.getOutput().embeddableLoaded[embeddable2.id]).toBe(true); -}); - -test('Container changes made directly after adding a new embeddable are propagated', async () => { - const coreSetup = coreMock.createSetup(); - const coreStart = coreMock.createStart(); - const { setup, doStart, uiActions } = testPlugin(coreSetup, coreStart); - - const factory = new SlowContactCardEmbeddableFactory({ - loadTickCount: 3, - execAction: uiActions.executeTriggerActions, - }); - setup.registerEmbeddableFactory(factory.type, factory); - - const start = doStart(); - - const container = new HelloWorldContainer( - { - id: 'hello', - panels: {}, - viewMode: ViewMode.EDIT, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - const subscription = Rx.merge(container.getOutput$(), container.getInput$()) - .pipe(skip(2)) - .subscribe(() => { - expect(Object.keys(container.getOutput().embeddableLoaded).length).toBe(1); - if (Object.keys(container.getOutput().embeddableLoaded).length > 0) { - const embeddableId = Object.keys(container.getOutput().embeddableLoaded)[0]; - - if (container.getOutput().embeddableLoaded[embeddableId] === true) { - const embeddable = container.getChild(embeddableId); - if (embeddable.getInput().viewMode === ViewMode.VIEW) { - subscription.unsubscribe(); - } - } - } - }); - - container.addNewEmbeddable(CONTACT_CARD_EMBEDDABLE, { - firstName: 'A girl', - lastName: 'has no name', - }); - - container.updateInput({ viewMode: ViewMode.VIEW }); -}); - -test('container stores ErrorEmbeddables when a factory for a child cannot be found (so the panel can be removed)', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels: { - '123': { - type: 'IDontExist', - explicitInput: { id: '123' }, - }, - }, - viewMode: ViewMode.EDIT, - }); - - container.getOutput$().subscribe(() => { - if (container.getOutput().embeddableLoaded['123']) { - const child = container.getChild('123'); - expect(child.type).toBe(ERROR_EMBEDDABLE_TYPE); - } - }); -}); - -test('container stores ErrorEmbeddables when a saved object cannot be found', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels: { - '123': { - type: 'vis', - explicitInput: { id: '123', savedObjectId: '456' } as SavedObjectEmbeddableInput, - }, - }, - viewMode: ViewMode.EDIT, - }); - - container.getOutput$().subscribe(() => { - if (container.getOutput().embeddableLoaded['123']) { - const child = container.getChild('123'); - expect(child.type).toBe(ERROR_EMBEDDABLE_TYPE); - } - }); -}); - -test('ErrorEmbeddables get updated when parent does', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels: { - '123': { - type: 'vis', - explicitInput: { id: '123', savedObjectId: '456' } as SavedObjectEmbeddableInput, - }, - }, - viewMode: ViewMode.EDIT, - }); - - container.getOutput$().subscribe(() => { - if (container.getOutput().embeddableLoaded['123']) { - const embeddable = container.getChild('123'); - - expect(embeddable.getInput().viewMode).toBe(ViewMode.EDIT); - - container.updateInput({ viewMode: ViewMode.VIEW }); - - expect(embeddable.getInput().viewMode).toBe(ViewMode.VIEW); - } - }); -}); - -test('untilEmbeddableLoaded() throws an error if there is no such child panel in the container', async () => { - const { container } = await createHelloWorldContainerAndEmbeddable({ - id: 'hello', - panels: {}, - }); - - expect(container.untilEmbeddableLoaded('idontexist')).rejects.toThrowError(); -}); - -test('untilEmbeddableLoaded() throws an error if there is no such child panel in the container - 2', async () => { - const { doStart } = testPlugin(coreMock.createSetup(), coreMock.createStart()); - const start = doStart(); - const container = new HelloWorldContainer( - { - id: 'hello', - panels: {}, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - const [, error] = await of(container.untilEmbeddableLoaded('123')); - expect(error).toBeInstanceOf(Error); - expect((error as Error).message).toMatchInlineSnapshot(`"Panel not found"`); -}); - -test('untilEmbeddableLoaded() resolves if child is loaded in the container', async () => { - const { setup, doStart } = testPlugin(coreMock.createSetup(), coreMock.createStart()); - const factory = new HelloWorldEmbeddableFactoryDefinition(); - setup.registerEmbeddableFactory(factory.type, factory); - const start = doStart(); - const container = new HelloWorldContainer( - { - id: 'hello', - panels: { - '123': { - type: HELLO_WORLD_EMBEDDABLE, - explicitInput: { id: '123' }, - }, - }, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - const child = await container.untilEmbeddableLoaded('123'); - expect(child).toBeDefined(); - expect(child.type).toBe(HELLO_WORLD_EMBEDDABLE); -}); - -test('untilEmbeddableLoaded resolves with undefined if child is subsequently removed', async () => { - const { doStart, setup, uiActions } = testPlugin(coreMock.createSetup(), coreMock.createStart()); - const factory = new SlowContactCardEmbeddableFactory({ - loadTickCount: 3, - execAction: uiActions.executeTriggerActions, - }); - setup.registerEmbeddableFactory(factory.type, factory); - - const start = doStart(); - const container = new HelloWorldContainer( - { - id: 'hello', - panels: { - '123': { - explicitInput: { id: '123', firstName: 'Sam', lastName: 'Tarley' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - }, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - container.untilEmbeddableLoaded('123').then((embed) => { - expect(embed).toBeUndefined(); - }); - - container.updateInput({ panels: {} }); -}); - -test('adding a panel then subsequently removing it before its loaded removes the panel', (done) => { - const { doStart, uiActions, setup } = testPlugin(coreMock.createSetup(), coreMock.createStart()); - const factory = new SlowContactCardEmbeddableFactory({ - loadTickCount: 1, - execAction: uiActions.executeTriggerActions, - }); - setup.registerEmbeddableFactory(factory.type, factory); - const start = doStart(); - const container = new HelloWorldContainer( - { - id: 'hello', - panels: { - '123': { - explicitInput: { id: '123', firstName: 'Sam', lastName: 'Tarley' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - }, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - // Final state should be that the panel is removed. - Rx.merge(container.getInput$(), container.getOutput$()).subscribe(() => { - if ( - container.getInput().panels['123'] === undefined && - container.getOutput().embeddableLoaded['123'] === undefined && - container.getInput().panels['456'] !== undefined && - container.getOutput().embeddableLoaded['456'] === true - ) { - done(); - } - }); - - container.updateInput({ panels: {} }); - - container.updateInput({ - panels: { - '456': { - explicitInput: { id: '456' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - }, - }); -}); diff --git a/src/plugins/embeddable/public/tests/explicit_input.test.ts b/src/plugins/embeddable/public/tests/explicit_input.test.ts deleted file mode 100644 index 60ed8378b4f8f..0000000000000 --- a/src/plugins/embeddable/public/tests/explicit_input.test.ts +++ /dev/null @@ -1,128 +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 { skip } from 'rxjs'; -import { testPlugin } from './test_plugin'; -import { - MockFilter, - FILTERABLE_EMBEDDABLE, - FilterableEmbeddableInput, -} from '../lib/test_samples/embeddables/filterable_embeddable'; -import { FilterableEmbeddableFactory } from '../lib/test_samples/embeddables/filterable_embeddable_factory'; -import { CONTACT_CARD_EMBEDDABLE } from '../lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory'; -import { SlowContactCardEmbeddableFactory } from '../lib/test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory'; -import { HELLO_WORLD_EMBEDDABLE, HelloWorldEmbeddableFactoryDefinition } from './fixtures'; -import { FilterableContainer } from '../lib/test_samples/embeddables/filterable_container'; -import { isErrorEmbeddable } from '../lib'; -import { HelloWorldContainer } from '../lib/test_samples/embeddables/hello_world_container'; -import { coreMock } from '@kbn/core/public/mocks'; - -const { setup, doStart, uiActions } = testPlugin(coreMock.createSetup(), coreMock.createStart()); - -setup.registerEmbeddableFactory(FILTERABLE_EMBEDDABLE, new FilterableEmbeddableFactory()); -const factory = new SlowContactCardEmbeddableFactory({ - loadTickCount: 2, - execAction: uiActions.executeTriggerActions, -}); -setup.registerEmbeddableFactory(CONTACT_CARD_EMBEDDABLE, factory); -setup.registerEmbeddableFactory( - HELLO_WORLD_EMBEDDABLE, - new HelloWorldEmbeddableFactoryDefinition() -); - -const start = doStart(); - -test('Explicit embeddable input mapped to undefined will default to inherited', async () => { - const derivedFilter: MockFilter = { - $state: { store: 'appState' }, - meta: { disabled: false, alias: 'name', negate: false }, - query: { match: {} }, - }; - const container = new FilterableContainer( - { id: 'hello', panels: {}, filters: [derivedFilter] }, - start.getEmbeddableFactory - ); - const embeddable = await container.addNewEmbeddable(FILTERABLE_EMBEDDABLE, {}); - - if (isErrorEmbeddable(embeddable)) { - throw new Error('Error adding embeddable'); - } - - embeddable.updateInput({ filters: [] }); - - expect(container.getInputForChild(embeddable.id).filters).toEqual([]); - - embeddable.updateInput({ filters: undefined }); - - expect(container.getInputForChild(embeddable.id).filters).toEqual([ - derivedFilter, - ]); -}); - -test('Explicit embeddable input mapped to undefined with no inherited value will get passed to embeddable', async () => { - const container = new HelloWorldContainer( - { id: 'hello', panels: {} }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - const embeddable = await container.addNewEmbeddable(FILTERABLE_EMBEDDABLE, {}); - - if (isErrorEmbeddable(embeddable)) { - throw new Error('Error adding embeddable'); - } - - embeddable.updateInput({ filters: [] }); - - expect(container.getInputForChild(embeddable.id).filters).toEqual([]); - - const subscription = await embeddable - .getInput$() - .pipe(skip(1)) - .subscribe(() => { - if (embeddable.getInput().filters === undefined) { - subscription.unsubscribe(); - } - }); - - embeddable.updateInput({ filters: undefined }); -}); - -// The goal is to make sure that if the container input changes after `onPanelAdded` is called -// but before the embeddable factory returns the embeddable, that the `inheritedChildInput` and -// embeddable input comparisons won't cause explicit input to be set when it shouldn't. -test('Explicit input tests in async situations', (done: () => void) => { - const container = new HelloWorldContainer( - { - id: 'hello', - panels: { - '123': { - explicitInput: { firstName: 'Sam', id: '123' }, - type: CONTACT_CARD_EMBEDDABLE, - }, - }, - }, - { - getEmbeddableFactory: start.getEmbeddableFactory, - } - ); - - container.updateInput({ lastName: 'lolol' }); - - const subscription = container.getOutput$().subscribe(() => { - if (container.getOutput().embeddableLoaded['123']) { - const embeddable = container.getChild('123'); - expect(embeddable).toBeDefined(); - expect(embeddable.getInput().lastName).toBe('lolol'); - subscription.unsubscribe(); - done(); - } - }); -}); diff --git a/src/plugins/embeddable/public/tests/get_embeddable_factories.test.ts b/src/plugins/embeddable/public/tests/get_embeddable_factories.test.ts deleted file mode 100644 index 6b7794958ad54..0000000000000 --- a/src/plugins/embeddable/public/tests/get_embeddable_factories.test.ts +++ /dev/null @@ -1,40 +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 { testPlugin } from './test_plugin'; -import { FilterableContainerFactory } from '../lib/test_samples/embeddables/filterable_container_factory'; -import { ContactCardEmbeddableFactory } from '../lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory'; - -test('exports getEmbeddableFactories() function', () => { - const { doStart } = testPlugin(); - expect(typeof doStart().getEmbeddableFactories).toBe('function'); -}); - -test('returns empty list if there are no embeddable factories', () => { - const { doStart } = testPlugin(); - const start = doStart(); - const list = [...start.getEmbeddableFactories()]; - expect(list).toEqual([]); -}); - -test('returns existing embeddable factories', () => { - const { setup, doStart } = testPlugin(); - - const factory1 = new FilterableContainerFactory(async () => await start.getEmbeddableFactory); - const factory2 = new ContactCardEmbeddableFactory((() => null) as any, {} as any); - setup.registerEmbeddableFactory(factory1.type, factory1); - setup.registerEmbeddableFactory(factory2.type, factory2); - - const start = doStart(); - - const list = [...start.getEmbeddableFactories()]; - expect(list.length).toBe(2); - expect(!!list.find(({ type }) => factory1.type === type)).toBe(true); - expect(!!list.find(({ type }) => factory2.type === type)).toBe(true); -}); diff --git a/src/plugins/embeddable/public/tests/helpers.ts b/src/plugins/embeddable/public/tests/helpers.ts deleted file mode 100644 index d7fee9d13dec8..0000000000000 --- a/src/plugins/embeddable/public/tests/helpers.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 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 { coreMock } from '@kbn/core/public/mocks'; -import { ContainerInput, EmbeddableContainerSettings, isErrorEmbeddable } from '../lib'; -import { - ContactCardEmbeddable, - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, - CONTACT_CARD_EMBEDDABLE, - FilterableEmbeddableFactory, - HelloWorldContainer, - SlowContactCardEmbeddableFactory, -} from '../lib/test_samples'; -import { HelloWorldEmbeddableFactoryDefinition } from './fixtures'; -import { testPlugin } from './test_plugin'; - -export async function createHelloWorldContainerAndEmbeddable( - containerInput: ContainerInput = { id: 'hello', panels: {} }, - embeddableInput = {}, - settings?: EmbeddableContainerSettings -) { - const coreSetup = coreMock.createSetup(); - const coreStart = coreMock.createStart(); - const { setup, doStart, uiActions } = testPlugin(coreSetup, coreStart); - const filterableFactory = new FilterableEmbeddableFactory(); - const slowContactCardFactory = new SlowContactCardEmbeddableFactory({ - execAction: uiActions.executeTriggerActions, - }); - const contactCardCreateSpy = jest.spyOn(slowContactCardFactory, 'create'); - - const helloWorldFactory = new HelloWorldEmbeddableFactoryDefinition(); - - setup.registerEmbeddableFactory(filterableFactory.type, filterableFactory); - setup.registerEmbeddableFactory(slowContactCardFactory.type, slowContactCardFactory); - setup.registerEmbeddableFactory(helloWorldFactory.type, helloWorldFactory); - - const start = doStart(); - - const container = new HelloWorldContainer( - containerInput, - { - getEmbeddableFactory: start.getEmbeddableFactory, - }, - settings - ); - - const embeddable = await container.addNewEmbeddable< - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, - ContactCardEmbeddable - >(CONTACT_CARD_EMBEDDABLE, embeddableInput); - - if (isErrorEmbeddable(embeddable)) { - throw new Error('Error adding embeddable'); - } - - return { - setup, - start, - coreSetup, - coreStart, - container, - uiActions, - embeddable, - contactCardCreateSpy, - }; -} - -export const expectErrorAsync = (fn: (...args: unknown[]) => Promise): Promise => { - return fn() - .then(() => { - throw new Error('Expected an error throw.'); - }) - .catch((error) => { - if (error.message === 'Expected an error throw.') { - throw error; - } - return error; - }); -}; - -export const expectError = (fn: (...args: unknown[]) => unknown): Error => { - try { - fn(); - throw new Error('Expected an error throw.'); - } catch (error) { - if (error.message === 'Expected an error throw.') { - throw error; - } - return error; - } -}; - -export const of = async >( - promise: P -): Promise<[T | undefined, Error | unknown]> => { - try { - return [await promise, undefined]; - } catch (error) { - return [, error]; - } -}; diff --git a/src/plugins/embeddable/tsconfig.json b/src/plugins/embeddable/tsconfig.json index c3b5925e33233..58bd02e0493a8 100644 --- a/src/plugins/embeddable/tsconfig.json +++ b/src/plugins/embeddable/tsconfig.json @@ -10,7 +10,6 @@ "@kbn/saved-objects-plugin", "@kbn/kibana-utils-plugin", "@kbn/ui-actions-plugin", - "@kbn/i18n-react", "@kbn/utility-types", "@kbn/es-query", "@kbn/i18n", diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 3e1da4621dad2..79e730b87d1d3 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -2826,9 +2826,6 @@ "embeddableApi.panelNotificationTrigger.title": "Notifications du panneau", "embeddableApi.reactEmbeddable.factoryAlreadyExistsError": "Une usine incorporable pour le type : {key} est déjà enregistrée.", "embeddableApi.reactEmbeddable.factoryNotFoundError": "Aucune usine incorporable n'a été trouvée pour le type : {key}", - "embeddableApi.samples.contactCard.displayName": "carte de visite", - "embeddableApi.samples.filterableContainer.displayName": "tableau de bord filtrable", - "embeddableApi.samples.filterableEmbeddable.displayName": "filtrable", "embeddableApi.selectRangeTrigger.description": "Une plage de valeurs sur la visualisation", "embeddableApi.selectRangeTrigger.title": "Sélection de la plage", "embeddableApi.valueClickTrigger.description": "Un point de données cliquable sur la visualisation", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 8a903f40c4dc0..a58158260f173 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -2821,9 +2821,6 @@ "embeddableApi.panelNotificationTrigger.title": "パネル通知", "embeddableApi.reactEmbeddable.factoryAlreadyExistsError": "タイプ\"{key}\"の埋め込み可能ファクトリはすでに登録されています。", "embeddableApi.reactEmbeddable.factoryNotFoundError": "タイプ\"{key}\"の埋め込み可能ファクトリが見つかりません", - "embeddableApi.samples.contactCard.displayName": "連絡先カード", - "embeddableApi.samples.filterableContainer.displayName": "フィルター可能なダッシュボード", - "embeddableApi.samples.filterableEmbeddable.displayName": "フィルター可能", "embeddableApi.selectRangeTrigger.description": "ビジュアライゼーションでの値の範囲", "embeddableApi.selectRangeTrigger.title": "範囲選択", "embeddableApi.valueClickTrigger.description": "ビジュアライゼーションでデータポイントをクリック", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index ed461f1a877ad..8954fba54b002 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -2811,9 +2811,6 @@ "embeddableApi.panelNotificationTrigger.title": "面板通知", "embeddableApi.reactEmbeddable.factoryAlreadyExistsError": "已注册类型为 {key} 的可嵌入工厂。", "embeddableApi.reactEmbeddable.factoryNotFoundError": "未找到类型为 {key} 的可嵌入工厂", - "embeddableApi.samples.contactCard.displayName": "联系卡片", - "embeddableApi.samples.filterableContainer.displayName": "可筛选仪表板", - "embeddableApi.samples.filterableEmbeddable.displayName": "可筛选", "embeddableApi.selectRangeTrigger.description": "可视化上的值范围", "embeddableApi.selectRangeTrigger.title": "范围选择", "embeddableApi.valueClickTrigger.description": "可视化上的数据点单击",