From d508b5da9ce4664565c1594d23688663eff66522 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 5 Dec 2024 12:55:40 -0700 Subject: [PATCH] [embeddable] remove legacy embeddable factories from 'Add from library' flyout (#202823) Part of https://github.com/elastic/kibana/issues/180059 PR removes legacy embeddable factory support from Canvas and Dashboard `Add from library` flyout PR also does the following clean-ups 1) Renames folder, files, and component from `add_panel_flyout` to `add_from_library_flyout`. When component was originally created, dashboard `Add panel` button did not exist, and `Add from library` button was called `Add panel`. Now that dashboard contains `Add panel` and `Add from library` buttons, the old naming convention is super confusing and not longer lines up with the current UI. 2) moves registry to `add_from_library` folder so that the registry is in closer proximity to its usage. 2) Renames `registerReactEmbeddableSavedObject` to `registerAddFromLibraryType` because `registerReactEmbeddableSavedObject` does not clearly specifying what the registry enables. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine --- .../public/app/register_embeddable.tsx | 11 +- .../register_saved_object_example.ts | 3 +- .../embeddable/api/add_panel_from_library.ts | 8 +- src/plugins/discover/public/plugin.tsx | 3 +- .../add_from_library_flyout.test.tsx | 111 +++++++++ .../add_from_library_flyout.tsx | 109 +++++++++ .../open_add_from_library_flyout.tsx} | 19 +- .../registry.ts} | 51 ++-- .../add_panel_flyout.test.tsx | 196 --------------- .../add_panel_flyout/add_panel_flyout.tsx | 224 ------------------ src/plugins/embeddable/public/index.ts | 4 +- .../embeddable_saved_object_registry/index.ts | 14 -- src/plugins/embeddable/public/lib/index.ts | 1 - src/plugins/embeddable/public/mocks.tsx | 11 +- src/plugins/embeddable/public/plugin.tsx | 30 +-- .../registry/saved_object_to_panel_methods.ts | 28 --- src/plugins/links/public/plugin.ts | 3 +- src/plugins/visualizations/public/plugin.ts | 3 +- .../embeddable_flyout/flyout.component.tsx | 97 +------- x-pack/plugins/lens/public/plugin.ts | 3 +- .../react_embeddable/setup_map_embeddable.ts | 3 +- .../add_from_library_button/index.tsx | 4 +- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 25 files changed, 284 insertions(+), 658 deletions(-) create mode 100644 src/plugins/embeddable/public/add_from_library/add_from_library_flyout.test.tsx create mode 100644 src/plugins/embeddable/public/add_from_library/add_from_library_flyout.tsx rename src/plugins/embeddable/public/{add_panel_flyout/open_add_panel_flyout.tsx => add_from_library/open_add_from_library_flyout.tsx} (74%) rename src/plugins/embeddable/public/{lib/embeddable_saved_object_registry/embeddable_saved_object_registry.ts => add_from_library/registry.ts} (56%) delete mode 100644 src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.test.tsx delete mode 100644 src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx delete mode 100644 src/plugins/embeddable/public/lib/embeddable_saved_object_registry/index.ts delete mode 100644 src/plugins/embeddable/public/registry/saved_object_to_panel_methods.ts diff --git a/examples/embeddable_examples/public/app/register_embeddable.tsx b/examples/embeddable_examples/public/app/register_embeddable.tsx index 0f3217824f943..836eaa8f06209 100644 --- a/examples/embeddable_examples/public/app/register_embeddable.tsx +++ b/examples/embeddable_examples/public/app/register_embeddable.tsx @@ -81,13 +81,14 @@ export const RegisterEmbeddable = () => { -

Saved object embeddables

+

+ Show saved object type in Add from library menu +

Embeddable factories, such as Lens, Maps, Links, that can reference saved objects should - register their saved object types using{' '} - registerReactEmbeddableSavedObject. The Add from library flyout - on Dashboards uses this registry to list saved objects. The example function below could - be called from the public start contract for a plugin. + register their saved object types using registerAddFromLibraryType. The{' '} + Add from library flyout on Dashboards uses this registry to list saved objects. + The example function below could be called from the public start contract for a plugin.

diff --git a/examples/embeddable_examples/public/react_embeddables/register_saved_object_example.ts b/examples/embeddable_examples/public/react_embeddables/register_saved_object_example.ts index b43bffd42d87b..15082ef701693 100644 --- a/examples/embeddable_examples/public/react_embeddables/register_saved_object_example.ts +++ b/examples/embeddable_examples/public/react_embeddables/register_saved_object_example.ts @@ -14,14 +14,13 @@ const MY_SAVED_OBJECT_TYPE = 'mySavedObjectType'; const APP_ICON = 'logoKibana'; export const registerMyEmbeddableSavedObject = (embeddableSetup: EmbeddableSetup) => - embeddableSetup.registerReactEmbeddableSavedObject({ + embeddableSetup.registerAddFromLibraryType({ onAdd: (container, savedObject) => { container.addNewPanel({ panelType: MY_EMBEDDABLE_TYPE, initialState: savedObject.attributes, }); }, - embeddableType: MY_EMBEDDABLE_TYPE, savedObjectType: MY_SAVED_OBJECT_TYPE, savedObjectName: 'Some saved object', getIconForSavedObject: () => APP_ICON, diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts index ba31677840aca..f5e76cff53b08 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts @@ -7,18 +7,14 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { isErrorEmbeddable, openAddPanelFlyout } from '@kbn/embeddable-plugin/public'; +import { isErrorEmbeddable, openAddFromLibraryFlyout } from '@kbn/embeddable-plugin/public'; import { DashboardContainer } from '../dashboard_container'; export function addFromLibrary(this: DashboardContainer) { if (isErrorEmbeddable(this)) return; this.openOverlay( - openAddPanelFlyout({ + openAddFromLibraryFlyout({ container: this, - onAddPanel: (id: string) => { - this.setScrollToPanelId(id); - this.setHighlightPanelId(id); - }, onClose: () => { this.clearOverlays(); }, diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index e29922d05f2c0..959ea78d50ecb 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -412,7 +412,7 @@ export class DiscoverPlugin return this.getDiscoverServices(coreStart, deps, profilesManager, ebtManager); }; - plugins.embeddable.registerReactEmbeddableSavedObject({ + plugins.embeddable.registerAddFromLibraryType({ onAdd: async (container, savedObject) => { const services = await getDiscoverServicesForEmbeddable(); const initialState = await deserializeState({ @@ -427,7 +427,6 @@ export class DiscoverPlugin initialState, }); }, - embeddableType: SEARCH_EMBEDDABLE_TYPE, savedObjectType: SavedSearchType, savedObjectName: i18n.translate('discover.savedSearch.savedObjectName', { defaultMessage: 'Saved search', diff --git a/src/plugins/embeddable/public/add_from_library/add_from_library_flyout.test.tsx b/src/plugins/embeddable/public/add_from_library/add_from_library_flyout.test.tsx new file mode 100644 index 0000000000000..2dbf61aa7ebbd --- /dev/null +++ b/src/plugins/embeddable/public/add_from_library/add_from_library_flyout.test.tsx @@ -0,0 +1,111 @@ +/* + * 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 * as React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; + +import { AddFromLibraryFlyout } from './add_from_library_flyout'; +import { usageCollection } from '../kibana_services'; +import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks'; +import { registerAddFromLibraryType } from './registry'; +import { PresentationContainer } from '@kbn/presentation-containers'; +import { HasType } from '@kbn/presentation-publishing'; + +// Mock saved objects finder component so we can call the onChoose method. +jest.mock('@kbn/saved-objects-finder-plugin/public', () => { + return { + SavedObjectFinder: jest + .fn() + .mockImplementation( + ({ + onChoose, + }: { + onChoose: (id: string, type: string, name: string, so: unknown) => Promise; + }) => ( + <> + + + ) + ), + }; +}); + +describe('add from library flyout', () => { + let container: PresentationContainer & HasType; + const onAdd = jest.fn(); + + beforeAll(() => { + registerAddFromLibraryType({ + onAdd, + savedObjectType: 'AWESOME_EMBEDDABLE', + savedObjectName: 'Awesome sauce', + getIconForSavedObject: () => 'happyface', + }); + }); + + beforeEach(() => { + onAdd.mockClear(); + container = { + type: 'DASHBOARD_CONTAINER', + ...getMockPresentationContainer(), + }; + }); + + test('renders SavedObjectFinder', async () => { + const { container: componentContainer } = render( + + ); + + // component should not contain an extra flyout + // https://github.com/elastic/kibana/issues/64789 + const flyout = componentContainer.querySelector('.euiFlyout'); + expect(flyout).toBeNull(); + const dummyButton = screen.queryAllByTestId('soFinderAddButton'); + expect(dummyButton).toHaveLength(1); + }); + + test('calls the registered onAdd method', async () => { + render(); + expect(Object.values(container.children$.value).length).toBe(0); + fireEvent.click(screen.getByTestId('soFinderAddButton')); + // flush promises + await new Promise((r) => setTimeout(r, 1)); + + expect(onAdd).toHaveBeenCalledWith(container, {}); + }); + + test('runs telemetry function on add embeddable', async () => { + render(); + + expect(Object.values(container.children$.value).length).toBe(0); + fireEvent.click(screen.getByTestId('soFinderAddButton')); + // flush promises + await new Promise((r) => setTimeout(r, 1)); + + expect(usageCollection.reportUiCounter).toHaveBeenCalledWith( + 'DASHBOARD_CONTAINER', + 'click', + 'AWESOME_EMBEDDABLE:add' + ); + }); +}); diff --git a/src/plugins/embeddable/public/add_from_library/add_from_library_flyout.tsx b/src/plugins/embeddable/public/add_from_library/add_from_library_flyout.tsx new file mode 100644 index 0000000000000..3f68e5c2c08ab --- /dev/null +++ b/src/plugins/embeddable/public/add_from_library/add_from_library_flyout.tsx @@ -0,0 +1,109 @@ +/* + * 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, { useCallback } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; +import { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; +import { + SavedObjectFinder, + SavedObjectFinderProps, + type SavedObjectMetaData, +} from '@kbn/saved-objects-finder-plugin/public'; + +import { METRIC_TYPE } from '@kbn/analytics'; +import { apiHasType } from '@kbn/presentation-publishing'; +import { CanAddNewPanel } from '@kbn/presentation-containers'; +import { + core, + savedObjectsTaggingOss, + contentManagement, + usageCollection, +} from '../kibana_services'; +import { EmbeddableFactoryNotFoundError } from '../lib'; +import { getAddFromLibraryType, useAddFromLibraryTypes } from './registry'; + +const runAddTelemetry = ( + parent: unknown, + savedObject: SavedObjectCommon, + savedObjectMetaData: SavedObjectMetaData +) => { + if (!apiHasType(parent)) return; + const type = savedObjectMetaData.getSavedObjectSubType + ? savedObjectMetaData.getSavedObjectSubType(savedObject) + : savedObjectMetaData.type; + + usageCollection?.reportUiCounter?.(parent.type, METRIC_TYPE.CLICK, `${type}:add`); +}; + +export const AddFromLibraryFlyout = ({ + container, + modalTitleId, +}: { + container: CanAddNewPanel; + modalTitleId?: string; +}) => { + const libraryTypes = useAddFromLibraryTypes(); + + const onChoose: SavedObjectFinderProps['onChoose'] = useCallback( + async ( + id: SavedObjectCommon['id'], + type: SavedObjectCommon['type'], + name: string, + savedObject: SavedObjectCommon + ) => { + const libraryType = getAddFromLibraryType(type); + if (!libraryType) { + core.notifications.toasts.addWarning(new EmbeddableFactoryNotFoundError(type).message); + return; + } + + libraryType.onAdd(container, savedObject); + runAddTelemetry(container, savedObject, libraryType.savedObjectMetaData); + }, + [container] + ); + + return ( + <> + + +

+ {i18n.translate('embeddableApi.addPanel.Title', { defaultMessage: 'Add from library' })} +

+
+
+ + { + return item.managed + ? i18n.translate('embeddableApi.addPanel.managedPanelTooltip', { + defaultMessage: + 'Elastic manages this panel. Adding it to a dashboard unlinks it from the library.', + }) + : undefined; + }} + /> + + + ); +}; diff --git a/src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx b/src/plugins/embeddable/public/add_from_library/open_add_from_library_flyout.tsx similarity index 74% rename from src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx rename to src/plugins/embeddable/public/add_from_library/open_add_from_library_flyout.tsx index 9ba3c00a73745..8fe6f58c367c4 100644 --- a/src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/add_from_library/open_add_from_library_flyout.tsx @@ -17,32 +17,25 @@ import { CanAddNewPanel } from '@kbn/presentation-containers'; import { core } from '../kibana_services'; const LazyAddPanelFlyout = React.lazy(async () => { - const module = await import('./add_panel_flyout'); - return { default: module.AddPanelFlyout }; + const module = await import('./add_from_library_flyout'); + return { default: module.AddFromLibraryFlyout }; }); const htmlId = htmlIdGenerator('modalTitleId'); -export const openAddPanelFlyout = ({ +export const openAddFromLibraryFlyout = ({ container, - onAddPanel, onClose, }: { container: CanAddNewPanel; - onAddPanel?: (id: string) => void; onClose?: () => void; }): OverlayRef => { const modalTitleId = htmlId(); - // send the overlay ref to the root embeddable if it is capable of tracking overlays - const flyoutSession = core.overlays.openFlyout( + const flyoutRef = core.overlays.openFlyout( toMountPoint( }> - + , core ), @@ -60,5 +53,5 @@ export const openAddPanelFlyout = ({ } ); - return flyoutSession; + return flyoutRef; }; diff --git a/src/plugins/embeddable/public/lib/embeddable_saved_object_registry/embeddable_saved_object_registry.ts b/src/plugins/embeddable/public/add_from_library/registry.ts similarity index 56% rename from src/plugins/embeddable/public/lib/embeddable_saved_object_registry/embeddable_saved_object_registry.ts rename to src/plugins/embeddable/public/add_from_library/registry.ts index 785d56c55050c..03af6380ff239 100644 --- a/src/plugins/embeddable/public/lib/embeddable_saved_object_registry/embeddable_saved_object_registry.ts +++ b/src/plugins/embeddable/public/add_from_library/registry.ts @@ -8,54 +8,43 @@ */ import { IconType } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { CanAddNewPanel } from '@kbn/presentation-containers'; import { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public'; +import { useMemo } from 'react'; -type SOToEmbeddable = ( - container: CanAddNewPanel, - savedObject: SavedObjectCommon -) => void; - -export type ReactEmbeddableSavedObject< - TSavedObjectAttributes extends FinderAttributes = FinderAttributes -> = { - onAdd: SOToEmbeddable; +export type RegistryItem = { + onAdd: ( + container: CanAddNewPanel, + savedObject: SavedObjectCommon + ) => void; savedObjectMetaData: SavedObjectMetaData; }; -const registry: Map> = new Map(); +const registry: Map> = new Map(); -export const registerReactEmbeddableSavedObject = < - TSavedObjectAttributes extends FinderAttributes ->({ +export const registerAddFromLibraryType = ({ onAdd, - embeddableType, savedObjectType, savedObjectName, getIconForSavedObject, getSavedObjectSubType, getTooltipForSavedObject, }: { - onAdd: SOToEmbeddable; - embeddableType: string; + onAdd: RegistryItem['onAdd']; savedObjectType: string; savedObjectName: string; getIconForSavedObject: (savedObject: SavedObjectCommon) => IconType; getSavedObjectSubType?: (savedObject: SavedObjectCommon) => string; getTooltipForSavedObject?: (savedObject: SavedObjectCommon) => string; }) => { - if (registry.has(embeddableType)) { + if (registry.has(savedObjectType)) { throw new Error( - i18n.translate('embeddableApi.embeddableSavedObjectRegistry.keyAlreadyExistsError', { - defaultMessage: `Embeddable type {embeddableType} already exists in the registry.`, - values: { embeddableType }, - }) + `Saved object type '${savedObjectType}' already exists in the 'Add from Library' registry.` ); } - registry.set(embeddableType, { + registry.set(savedObjectType, { onAdd, savedObjectMetaData: { name: savedObjectName, @@ -67,10 +56,14 @@ export const registerReactEmbeddableSavedObject = < }); }; -export const getReactEmbeddableSavedObjects = < - TSavedObjectAttributes extends FinderAttributes ->() => { - return registry.entries() as IterableIterator< - [string, ReactEmbeddableSavedObject] - >; +export function useAddFromLibraryTypes() { + return useMemo(() => { + return [...registry.entries()] + .map(([type, registryItem]) => registryItem.savedObjectMetaData) + .sort((a, b) => a.type.localeCompare(b.type)); + }, []); +} + +export const getAddFromLibraryType = (type: string) => { + return registry.get(type); }; diff --git a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.test.tsx b/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.test.tsx deleted file mode 100644 index 11b895d2c7150..0000000000000 --- a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.test.tsx +++ /dev/null @@ -1,196 +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 * as React from 'react'; -import { coreMock } from '@kbn/core/public/mocks'; -import { fireEvent, render, screen } from '@testing-library/react'; -import { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; - -import { AddPanelFlyout } from './add_panel_flyout'; -import { core, embeddableStart, usageCollection } from '../kibana_services'; -import { ContactCardEmbeddableFactory } from '../lib/test_samples'; -import { Container, registerReactEmbeddableSavedObject } from '../lib'; -import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks'; - -// Mock saved objects finder component so we can call the onChoose method. -jest.mock('@kbn/saved-objects-finder-plugin/public', () => { - return { - SavedObjectFinder: jest - .fn() - .mockImplementation( - ({ - onChoose, - }: { - onChoose: (id: string, type: string, name: string, so: unknown) => Promise; - }) => ( - <> - - - - ) - ), - }; -}); - -describe('add panel flyout', () => { - describe('registered embeddables', () => { - let container: Container; - const onAdd = jest.fn(); - - beforeAll(() => { - registerReactEmbeddableSavedObject({ - onAdd, - embeddableType: 'AWESOME_EMBEDDABLE', - savedObjectType: 'AWESOME_EMBEDDABLE', - savedObjectName: 'Awesome sauce', - getIconForSavedObject: () => 'happyface', - }); - - embeddableStart.getEmbeddableFactories = jest.fn().mockReturnValue([]); - }); - - beforeEach(() => { - onAdd.mockClear(); - container = getMockPresentationContainer() as unknown as Container; - // @ts-ignore type is only expected on a dashboard container - container.type = 'DASHBOARD_CONTAINER'; - }); - - test('add panel flyout renders SavedObjectFinder', async () => { - const { container: componentContainer } = render(); - - // component should not contain an extra flyout - // https://github.com/elastic/kibana/issues/64789 - const flyout = componentContainer.querySelector('.euiFlyout'); - expect(flyout).toBeNull(); - const dummyButton = screen.queryAllByTestId('soFinderAddButton'); - expect(dummyButton).toHaveLength(1); - }); - - test('add panel calls the registered onAdd method', async () => { - render(); - expect(Object.values(container.children$.value).length).toBe(0); - fireEvent.click(screen.getByTestId('soFinderAddButton')); - // flush promises - await new Promise((r) => setTimeout(r, 1)); - - expect(onAdd).toHaveBeenCalledWith(container, {}); - }); - - test('runs telemetry function on add embeddable', async () => { - render(); - - expect(Object.values(container.children$.value).length).toBe(0); - fireEvent.click(screen.getByTestId('soFinderAddButton')); - // flush promises - await new Promise((r) => setTimeout(r, 1)); - - expect(usageCollection.reportUiCounter).toHaveBeenCalledWith( - 'DASHBOARD_CONTAINER', - 'click', - 'AWESOME_EMBEDDABLE:add' - ); - }); - }); - - describe('legacy embeddables', () => { - let container: Container; - - beforeEach(() => { - const coreStart = coreMock.createStart(); - const contactCardEmbeddableFactory = new ContactCardEmbeddableFactory( - (() => null) as any, - coreStart - ); - - embeddableStart.getEmbeddableFactories = jest - .fn() - .mockReturnValue([contactCardEmbeddableFactory]); - - container = getMockPresentationContainer() as unknown as Container; - container.addNewEmbeddable = jest.fn().mockResolvedValue({ id: 'foo' }); - // @ts-ignore type is only expected on a dashboard container - container.type = 'HELLO_WORLD_CONTAINER'; - }); - - test('add panel flyout renders SavedObjectFinder', async () => { - const { container: componentContainer } = render(); - - // component should not contain an extra flyout - // https://github.com/elastic/kibana/issues/64789 - const flyout = componentContainer.querySelector('.euiFlyout'); - expect(flyout).toBeNull(); - const dummyButton = screen.queryAllByTestId('soFinderAddLegacyButton'); - expect(dummyButton).toHaveLength(1); - }); - - test('add panel adds legacy embeddable to container', async () => { - render(); - expect(Object.values(container.children$.value).length).toBe(0); - fireEvent.click(screen.getByTestId('soFinderAddLegacyButton')); - // flush promises - await new Promise((r) => setTimeout(r, 1)); - - expect(container.addNewEmbeddable).toHaveBeenCalled(); - }); - - test('shows a success toast on add', async () => { - render(); - fireEvent.click(screen.getByTestId('soFinderAddLegacyButton')); - // flush promises - await new Promise((r) => setTimeout(r, 1)); - - expect(core.notifications.toasts.addSuccess).toHaveBeenCalledWith({ - 'data-test-subj': 'addObjectToContainerSuccess', - title: 'test name was added', - }); - }); - - test('runs telemetry function on add legacy embeddable', async () => { - render(); - - expect(Object.values(container.children$.value).length).toBe(0); - fireEvent.click(screen.getByTestId('soFinderAddLegacyButton')); - // flush promises - await new Promise((r) => setTimeout(r, 1)); - - expect(usageCollection.reportUiCounter).toHaveBeenCalledWith( - 'HELLO_WORLD_CONTAINER', - 'click', - 'CONTACT_CARD_EMBEDDABLE:add' - ); - }); - }); -}); diff --git a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx b/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx deleted file mode 100644 index 1bb7137479017..0000000000000 --- a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx +++ /dev/null @@ -1,224 +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, { useCallback, useMemo } from 'react'; - -import { i18n } from '@kbn/i18n'; -import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; -import { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; -import { - SavedObjectFinder, - SavedObjectFinderProps, - type SavedObjectMetaData, -} from '@kbn/saved-objects-finder-plugin/public'; - -import { METRIC_TYPE } from '@kbn/analytics'; -import { apiHasType } from '@kbn/presentation-publishing'; -import { Toast } from '@kbn/core/public'; -import { CanAddNewPanel } from '@kbn/presentation-containers'; -import { - core, - embeddableStart, - savedObjectsTaggingOss, - contentManagement, - usageCollection, -} from '../kibana_services'; -import { savedObjectToPanel } from '../registry/saved_object_to_panel_methods'; -import { - ReactEmbeddableSavedObject, - EmbeddableFactory, - EmbeddableFactoryNotFoundError, - getReactEmbeddableSavedObjects, - PanelIncompatibleError, -} from '../lib'; - -type LegacyFactoryMap = { [key: string]: EmbeddableFactory }; -type FactoryMap = { - [key: string]: ReactEmbeddableSavedObject & { type: string }; -}; - -type CanAddNewEmbeddable = { - addNewEmbeddable: (type: string, explicitInput: unknown, attributes: unknown) => { id: string }; -}; - -const apiCanAddNewEmbeddable = (api: unknown): api is CanAddNewEmbeddable => { - return typeof (api as CanAddNewEmbeddable).addNewEmbeddable === 'function'; -}; - -let lastToast: string | Toast; -const showSuccessToast = (name: string) => { - if (lastToast) core.notifications.toasts.remove(lastToast); - - lastToast = core.notifications.toasts.addSuccess({ - title: i18n.translate('embeddableApi.addPanel.savedObjectAddedToContainerSuccessMessageTitle', { - defaultMessage: '{savedObjectName} was added', - values: { - savedObjectName: name, - }, - }), - 'data-test-subj': 'addObjectToContainerSuccess', - }); -}; - -const runAddTelemetry = ( - parent: unknown, - factoryType: string, - savedObject: SavedObjectCommon, - savedObjectMetaData?: SavedObjectMetaData -) => { - if (!apiHasType(parent)) return; - const type = savedObjectMetaData?.getSavedObjectSubType - ? savedObjectMetaData.getSavedObjectSubType(savedObject) - : factoryType; - - usageCollection?.reportUiCounter?.(parent.type, METRIC_TYPE.CLICK, `${type}:add`); -}; - -export const AddPanelFlyout = ({ - container, - onAddPanel, - modalTitleId, -}: { - container: CanAddNewPanel; - onAddPanel?: (id: string) => void; - modalTitleId?: string; -}) => { - const legacyFactoriesBySavedObjectType: LegacyFactoryMap = useMemo(() => { - return [...embeddableStart.getEmbeddableFactories()] - .filter( - (embeddableFactory) => - Boolean(embeddableFactory.savedObjectMetaData?.type) && !embeddableFactory.isContainerType - ) - .reduce((acc, factory) => { - acc[factory.savedObjectMetaData!.type] = factory; - return acc; - }, {} as LegacyFactoryMap); - }, []); - - const factoriesBySavedObjectType: FactoryMap = useMemo(() => { - return [...getReactEmbeddableSavedObjects()] - .filter(([type, embeddableFactory]) => { - return Boolean(embeddableFactory.savedObjectMetaData?.type); - }) - .reduce((acc, [type, factory]) => { - acc[factory.savedObjectMetaData!.type] = { - ...factory, - type, - }; - return acc; - }, {} as FactoryMap); - }, []); - - const metaData = useMemo( - () => - [ - ...Object.values(factoriesBySavedObjectType), - ...Object.values(legacyFactoriesBySavedObjectType), - ] - .filter((embeddableFactory) => Boolean(embeddableFactory.savedObjectMetaData)) - .map(({ savedObjectMetaData }) => savedObjectMetaData!) - .sort((a, b) => a.type.localeCompare(b.type)), - [factoriesBySavedObjectType, legacyFactoriesBySavedObjectType] - ); - - const onChoose: SavedObjectFinderProps['onChoose'] = useCallback( - async ( - id: SavedObjectCommon['id'], - type: SavedObjectCommon['type'], - name: string, - savedObject: SavedObjectCommon - ) => { - if (factoriesBySavedObjectType[type]) { - const factory = factoriesBySavedObjectType[type]; - const { onAdd, savedObjectMetaData } = factory; - - onAdd(container, savedObject); - runAddTelemetry(container, factory.type, savedObject, savedObjectMetaData); - return; - } - - const legacyFactoryForSavedObjectType = legacyFactoriesBySavedObjectType[type]; - if (!legacyFactoryForSavedObjectType) { - throw new EmbeddableFactoryNotFoundError(type); - } - - // container.addNewEmbeddable is required for legacy embeddables to support - // panel placement strategies - if (!apiCanAddNewEmbeddable(container)) { - throw new PanelIncompatibleError(); - } - - let embeddableId: string; - - if (savedObjectToPanel[type]) { - // this panel type has a custom method for converting saved objects to panels - const panel = savedObjectToPanel[type](savedObject); - - const { id: _embeddableId } = await container.addNewEmbeddable( - legacyFactoryForSavedObjectType.type, - panel, - savedObject.attributes - ); - - embeddableId = _embeddableId; - } else { - const { id: _embeddableId } = await container.addNewEmbeddable( - legacyFactoryForSavedObjectType.type, - { savedObjectId: id }, - savedObject.attributes - ); - - embeddableId = _embeddableId; - } - - onAddPanel?.(embeddableId); - - showSuccessToast(name); - const { savedObjectMetaData, type: factoryType } = legacyFactoryForSavedObjectType; - runAddTelemetry(container, factoryType, savedObject, savedObjectMetaData); - }, - [container, factoriesBySavedObjectType, legacyFactoriesBySavedObjectType, onAddPanel] - ); - - return ( - <> - - -

- {i18n.translate('embeddableApi.addPanel.Title', { defaultMessage: 'Add from library' })} -

-
-
- - { - return item.managed - ? i18n.translate('embeddableApi.addPanel.managedPanelTooltip', { - defaultMessage: - 'Elastic manages this panel. Adding it to a dashboard unlinks it from the library.', - }) - : undefined; - }} - /> - - - ); -}; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index e6e3a4bb3fe04..25a25b2447146 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -10,7 +10,8 @@ import { PluginInitializerContext } from '@kbn/core/public'; import { EmbeddablePublicPlugin } from './plugin'; -export { openAddPanelFlyout } from './add_panel_flyout/open_add_panel_flyout'; +export { useAddFromLibraryTypes } from './add_from_library/registry'; +export { openAddFromLibraryFlyout } from './add_from_library/open_add_from_library_flyout'; export { EmbeddablePanel } from './embeddable_panel'; export { cellValueTrigger, @@ -80,7 +81,6 @@ export type { PanelState, PropertySpec, RangeSelectContext, - ReactEmbeddableSavedObject, ReferenceOrValueEmbeddable, SavedObjectEmbeddableInput, SelfStyledEmbeddable, diff --git a/src/plugins/embeddable/public/lib/embeddable_saved_object_registry/index.ts b/src/plugins/embeddable/public/lib/embeddable_saved_object_registry/index.ts deleted file mode 100644 index c0d7cdecb86b3..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddable_saved_object_registry/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export { - type ReactEmbeddableSavedObject, - getReactEmbeddableSavedObjects, - registerReactEmbeddableSavedObject, -} from './embeddable_saved_object_registry'; diff --git a/src/plugins/embeddable/public/lib/index.ts b/src/plugins/embeddable/public/lib/index.ts index e20fbfbe2bcf3..bcae2e69ec407 100644 --- a/src/plugins/embeddable/public/lib/index.ts +++ b/src/plugins/embeddable/public/lib/index.ts @@ -17,4 +17,3 @@ export * from './reference_or_value_embeddable'; export * from './self_styled_embeddable'; export * from './filterable_embeddable'; export * from './factory_migrations/run_factory_migrations'; -export * from './embeddable_saved_object_registry'; diff --git a/src/plugins/embeddable/public/mocks.tsx b/src/plugins/embeddable/public/mocks.tsx index cd95c08702732..fcabaa7cdb6c7 100644 --- a/src/plugins/embeddable/public/mocks.tsx +++ b/src/plugins/embeddable/public/mocks.tsx @@ -33,14 +33,13 @@ import { SelfStyledEmbeddable, } from '.'; import { setKibanaServices } from './kibana_services'; -import { registerReactEmbeddableSavedObject } from './lib'; import { SelfStyledOptions } from './lib/self_styled_embeddable/types'; import { EmbeddablePublicPlugin } from './plugin'; import { reactEmbeddableRegistryHasKey, registerReactEmbeddableFactory, } from './react_embeddable_system'; -import { registerSavedObjectToPanelMethod } from './registry/saved_object_to_panel_methods'; +import { registerAddFromLibraryType } from './add_from_library/registry'; export { mockAttributeService } from './lib/attribute_service/attribute_service.mock'; export type Setup = jest.Mocked; @@ -100,12 +99,7 @@ export function mockFilterableEmbeddable( const createSetupContract = (): Setup => { const setupContract: Setup = { - registerSavedObjectToPanelMethod: jest - .fn() - .mockImplementation(registerSavedObjectToPanelMethod), - registerReactEmbeddableSavedObject: jest - .fn() - .mockImplementation(registerReactEmbeddableSavedObject), + registerAddFromLibraryType: jest.fn().mockImplementation(registerAddFromLibraryType), registerReactEmbeddableFactory: jest.fn().mockImplementation(registerReactEmbeddableFactory), registerEmbeddableFactory: jest.fn(), registerEnhancement: jest.fn(), @@ -117,7 +111,6 @@ const createSetupContract = (): Setup => { const createStartContract = (): Start => { const startContract: Start = { reactEmbeddableRegistryHasKey: jest.fn().mockImplementation(reactEmbeddableRegistryHasKey), - getReactEmbeddableSavedObjects: jest.fn(), getEmbeddableFactories: jest.fn(), getEmbeddableFactory: jest.fn(), telemetry: jest.fn(), diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 12625a597afd4..801b518a0bd01 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -25,7 +25,6 @@ import { migrateToLatest, PersistableStateService } from '@kbn/kibana-utils-plug import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; import { EmbeddableFactoryRegistry, EmbeddableFactoryProvider, @@ -41,9 +40,6 @@ import { defaultEmbeddableFactoryProvider, IEmbeddable, SavedObjectEmbeddableInput, - registerReactEmbeddableSavedObject, - ReactEmbeddableSavedObject, - getReactEmbeddableSavedObjects, } from './lib'; import { EmbeddableFactoryDefinition } from './lib/embeddables/embeddable_factory_definition'; import { EmbeddableStateTransfer } from './lib/state_transfer'; @@ -62,7 +58,7 @@ import { reactEmbeddableRegistryHasKey, registerReactEmbeddableFactory, } from './react_embeddable_system'; -import { registerSavedObjectToPanelMethod } from './registry/saved_object_to_panel_methods'; +import { registerAddFromLibraryType } from './add_from_library/registry'; export interface EmbeddableSetupDependencies { uiActions: UiActionsSetup; @@ -79,17 +75,16 @@ export interface EmbeddableStartDependencies { export interface EmbeddableSetup { /** - * Register an embeddable API saved object with the Add from library flyout. + * Register a saved object type with the "Add from library" flyout. * * @example - * registerReactEmbeddableSavedObject({ + * registerAddFromLibraryType({ * onAdd: (container, savedObject) => { * container.addNewPanel({ * panelType: CONTENT_ID, * initialState: savedObject.attributes, * }); * }, - * embeddableType: CONTENT_ID, * savedObjectType: MAP_SAVED_OBJECT_TYPE, * savedObjectName: i18n.translate('xpack.maps.mapSavedObjectLabel', { * defaultMessage: 'Map', @@ -97,12 +92,7 @@ export interface EmbeddableSetup { * getIconForSavedObject: () => APP_ICON, * }); */ - registerReactEmbeddableSavedObject: typeof registerReactEmbeddableSavedObject; - - /** - * @deprecated React embeddables should register their saved objects with {@link registerReactEmbeddableSavedObject}. - */ - registerSavedObjectToPanelMethod: typeof registerSavedObjectToPanelMethod; + registerAddFromLibraryType: typeof registerAddFromLibraryType; /** * Registers an async {@link ReactEmbeddableFactory} getter. @@ -136,14 +126,6 @@ export interface EmbeddableStart extends PersistableStateService boolean; - /** - * - * @returns An iterator over all {@link ReactEmbeddableSavedObject}s that have been registered using {@link registerReactEmbeddableSavedObject}. - */ - getReactEmbeddableSavedObjects: < - TSavedObjectAttributes extends FinderAttributes - >() => IterableIterator<[string, ReactEmbeddableSavedObject]>; - /** * @deprecated use {@link registerReactEmbeddableFactory} instead. */ @@ -192,8 +174,7 @@ export class EmbeddablePublicPlugin implements Plugin = ( - // @ts-expect-error upgrade typescript v4.9.5 - savedObject: SavedObjectCommon -) => { savedObjectId: string } | Partial; - -export const savedObjectToPanel: Record> = {}; - -/** - * @deprecated - * React embeddables should register their saved object types with the registerReactEmbeddableSavedObject registry. - */ -export const registerSavedObjectToPanelMethod = ( - savedObjectType: string, - method: SavedObjectToPanelMethod -) => { - savedObjectToPanel[savedObjectType] = method; -}; diff --git a/src/plugins/links/public/plugin.ts b/src/plugins/links/public/plugin.ts index add09c8c2514b..05b9faf59c7b8 100644 --- a/src/plugins/links/public/plugin.ts +++ b/src/plugins/links/public/plugin.ts @@ -61,7 +61,7 @@ export class LinksPlugin name: APP_NAME, }); - plugins.embeddable.registerReactEmbeddableSavedObject({ + plugins.embeddable.registerAddFromLibraryType({ onAdd: async (container, savedObject) => { const initialState = await deserializeLinksSavedObject(savedObject); container.addNewPanel({ @@ -69,7 +69,6 @@ export class LinksPlugin initialState, }); }, - embeddableType: CONTENT_ID, savedObjectType: CONTENT_ID, savedObjectName: APP_NAME, getIconForSavedObject: () => APP_ICON, diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts index fcb3dc5137161..856c16104b6ca 100644 --- a/src/plugins/visualizations/public/plugin.ts +++ b/src/plugins/visualizations/public/plugin.ts @@ -411,14 +411,13 @@ export class VisualizationsPlugin const getVisualizeEmbeddableFactory = await getVisualizeEmbeddableFactoryLazy(); return getVisualizeEmbeddableFactory({ embeddableStart, embeddableEnhancedStart }); }); - embeddable.registerReactEmbeddableSavedObject({ + embeddable.registerAddFromLibraryType({ onAdd: (container, savedObject) => { container.addNewPanel({ panelType: VISUALIZE_EMBEDDABLE_TYPE, initialState: { savedObjectId: savedObject.id }, }); }, - embeddableType: VISUALIZE_EMBEDDABLE_TYPE, savedObjectType: VISUALIZE_EMBEDDABLE_TYPE, savedObjectName: i18n.translate('visualizations.visualizeSavedObjectName', { defaultMessage: 'Visualization', diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index 543367fda127a..52454a10ca732 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -9,14 +9,9 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eu import { i18n } from '@kbn/i18n'; import React, { FC, useCallback, useMemo } from 'react'; -import { EmbeddableFactory, ReactEmbeddableSavedObject } from '@kbn/embeddable-plugin/public'; -import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; -import { SavedObjectFinder, SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public'; -import { - contentManagementService, - coreServices, - embeddableService, -} from '../../services/kibana_services'; +import { useAddFromLibraryTypes } from '@kbn/embeddable-plugin/public'; +import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; +import { contentManagementService, coreServices } from '../../services/kibana_services'; const strings = { getNoItemsText: () => @@ -29,13 +24,6 @@ const strings = { }), }; -interface LegacyFactoryMap { - [key: string]: EmbeddableFactory; -} -interface FactoryMap { - [key: string]: ReactEmbeddableSavedObject & { type: string }; -} - export interface Props { onClose: () => void; onSelect: (id: string, embeddableType: string, isByValueEnabled?: boolean) => void; @@ -49,81 +37,18 @@ export const AddEmbeddableFlyout: FC = ({ onClose, isByValueEnabled, }) => { - const legacyFactoriesBySavedObjectType: LegacyFactoryMap = useMemo(() => { - return [...embeddableService.getEmbeddableFactories()] - .filter( - (embeddableFactory) => - Boolean(embeddableFactory.savedObjectMetaData?.type) && !embeddableFactory.isContainerType - ) - .reduce((acc, factory) => { - acc[factory.savedObjectMetaData!.type] = factory; - return acc; - }, {} as LegacyFactoryMap); - }, []); + const libraryTypes = useAddFromLibraryTypes(); - const factoriesBySavedObjectType: FactoryMap = useMemo(() => { - return [...embeddableService.getReactEmbeddableSavedObjects()] - .filter(([type, embeddableFactory]) => { - return Boolean(embeddableFactory.savedObjectMetaData?.type); - }) - .reduce((acc, [type, factory]) => { - acc[factory.savedObjectMetaData!.type] = { - ...factory, - type, - }; - return acc; - }, {} as FactoryMap); - }, []); - - const metaData = useMemo( - () => - [ - ...Object.values(factoriesBySavedObjectType), - ...Object.values(legacyFactoriesBySavedObjectType), - ] - .filter((factory) => - Boolean( - factory.type !== 'links' && // Links panels only exist on Dashboards - (isByValueEnabled || availableEmbeddables.includes(factory.type)) - ) - ) - .map((factory) => factory.savedObjectMetaData) - .filter>(function ( - maybeSavedObjectMetaData - ): maybeSavedObjectMetaData is SavedObjectMetaData<{}> { - return maybeSavedObjectMetaData !== undefined; - }) - .sort((a, b) => a.type.localeCompare(b.type)), - [ - availableEmbeddables, - factoriesBySavedObjectType, - isByValueEnabled, - legacyFactoriesBySavedObjectType, - ] - ); + const canvasOnlyLibraryTypes = useMemo(() => { + // Links panels are not supported in Canvas + return libraryTypes.filter(({ type }) => type !== 'links'); + }, [libraryTypes]); const onAddPanel = useCallback( (id: string, savedObjectType: string) => { - if (factoriesBySavedObjectType[savedObjectType]) { - const factory = factoriesBySavedObjectType[savedObjectType]; - const { type } = factory; - onSelect(id, type, isByValueEnabled); - return; - } - const embeddableFactories = embeddableService.getEmbeddableFactories(); - // Find the embeddable type from the saved object type - const found = Array.from(embeddableFactories).find((embeddableFactory) => { - return Boolean( - embeddableFactory.savedObjectMetaData && - embeddableFactory.savedObjectMetaData.type === savedObjectType - ); - }); - - const foundEmbeddableType = found ? found.type : 'unknown'; - - onSelect(id, foundEmbeddableType, isByValueEnabled); + onSelect(id, savedObjectType, isByValueEnabled); }, - [isByValueEnabled, onSelect, factoriesBySavedObjectType] + [isByValueEnabled, onSelect] ); return ( @@ -137,7 +62,7 @@ export const AddEmbeddableFlyout: FC = ({ ({ + embeddable.registerAddFromLibraryType({ onAdd: async (container, savedObject) => { const { attributeService } = await getStartServicesForEmbeddable(); // deserialize the saved object from visualize library @@ -411,7 +411,6 @@ export class LensPlugin { initialState: state, }); }, - embeddableType: LENS_EMBEDDABLE_TYPE, savedObjectType: LENS_EMBEDDABLE_TYPE, savedObjectName: i18n.translate('xpack.lens.mapSavedObjectLabel', { defaultMessage: 'Lens', diff --git a/x-pack/plugins/maps/public/react_embeddable/setup_map_embeddable.ts b/x-pack/plugins/maps/public/react_embeddable/setup_map_embeddable.ts index efaf3238a8068..5859bde4a173d 100644 --- a/x-pack/plugins/maps/public/react_embeddable/setup_map_embeddable.ts +++ b/x-pack/plugins/maps/public/react_embeddable/setup_map_embeddable.ts @@ -22,14 +22,13 @@ export function setupMapEmbeddable(embeddableSetup: EmbeddableSetup) { return mapEmbeddableFactory; }); - embeddableSetup.registerReactEmbeddableSavedObject({ + embeddableSetup.registerAddFromLibraryType({ onAdd: (container, savedObject) => { container.addNewPanel({ panelType: MAP_SAVED_OBJECT_TYPE, initialState: { savedObjectId: savedObject.id }, }); }, - embeddableType: MAP_SAVED_OBJECT_TYPE, savedObjectType: MAP_SAVED_OBJECT_TYPE, savedObjectName: i18n.translate('xpack.maps.mapSavedObjectLabel', { defaultMessage: 'Map', diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_from_library_button/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_from_library_button/index.tsx index a6befb3062ebb..282ae5cfc22a6 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_from_library_button/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_from_library_button/index.tsx @@ -7,7 +7,7 @@ import type { OverlayRef } from '@kbn/core/public'; import { v4 } from 'uuid'; -import { openAddPanelFlyout } from '@kbn/embeddable-plugin/public'; +import { openAddFromLibraryFlyout } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import type { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; import React, { useMemo, useRef } from 'react'; @@ -107,7 +107,7 @@ export function AddFromLibraryButton({ onItemAdd }: AddFromLibraryButtonProps) { data-test-subj="investigateAppAddFromLibraryButtonImportFromLibraryButton" iconType="importAction" onClick={() => { - panelRef.current = openAddPanelFlyout({ + panelRef.current = openAddFromLibraryFlyout({ container, }); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index c94eefe9c9034..63c26a6683173 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -2814,7 +2814,6 @@ "domDragDrop.keyboardInstructionsReorder": "Appuyez sur la barre d'espace ou sur Entrée pour commencer à faire glisser. Lors du glissement, utilisez les touches fléchées haut/bas pour réorganiser les éléments dans le groupe et les touches gauche/droite pour choisir les cibles de dépôt à l'extérieur du groupe. Appuyez à nouveau sur la barre d'espace ou sur Entrée pour terminer.", "embeddableApi.addPanel.managedPanelTooltip": "Elastic gère ce panneau. Le fait de l'ajouter à un tableau de bord le dissocie de la bibliothèque.", "embeddableApi.addPanel.noMatchingObjectsMessage": "Aucun objet correspondant trouvé.", - "embeddableApi.addPanel.savedObjectAddedToContainerSuccessMessageTitle": "{savedObjectName} a été ajouté.", "embeddableApi.addPanel.Title": "Ajouter depuis la bibliothèque", "embeddableApi.attributeService.saveToLibraryError": "Une erreur s'est produite lors de l'enregistrement. Erreur : {errorMessage}.", "embeddableApi.cellValueTrigger.description": "Les actions apparaissent dans les options de valeur de cellule dans la visualisation", @@ -2825,7 +2824,6 @@ "embeddableApi.compatibility.defaultTypeDisplayName": "graphique", "embeddableApi.contextMenuTrigger.description": "Une nouvelle action sera ajoutée au menu contextuel du panneau", "embeddableApi.contextMenuTrigger.title": "Menu contextuel", - "embeddableApi.embeddableSavedObjectRegistry.keyAlreadyExistsError": "Le type incorporable {embeddableType} existe déjà dans le registre.", "embeddableApi.errors.embeddableFactoryNotFound": "Impossible de charger {type}. Veuillez effectuer une mise à niveau vers la distribution par défaut d'Elasticsearch et de Kibana avec la licence appropriée.", "embeddableApi.errors.paneldoesNotExist": "Panneau introuvable", "embeddableApi.errors.panelIncompatibleError": "L'API du panneau n'est pas compatible", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b80f5e6427079..446ff88246a7a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2809,7 +2809,6 @@ "domDragDrop.keyboardInstructionsReorder": "スペースまたはEnterを押してドラッグを開始します。ドラッグするときには、上下矢印キーを使用すると、グループの項目を並べ替えます。左右矢印キーを使用すると、グループの外側でドロップ対象を選択します。もう一度スペースまたはEnterを押すと終了します。", "embeddableApi.addPanel.managedPanelTooltip": "Elasticはこのパネルを管理します。ダッシュボードに追加すると、ライブラリからリンクが解除されます。", "embeddableApi.addPanel.noMatchingObjectsMessage": "一致するオブジェクトが見つかりませんでした。", - "embeddableApi.addPanel.savedObjectAddedToContainerSuccessMessageTitle": "{savedObjectName} が追加されました", "embeddableApi.addPanel.Title": "ライブラリから追加", "embeddableApi.attributeService.saveToLibraryError": "保存中にエラーが発生しました。エラー:{errorMessage}", "embeddableApi.cellValueTrigger.description": "アクションはビジュアライゼーションのセル値オプションに表示されます", @@ -2820,7 +2819,6 @@ "embeddableApi.compatibility.defaultTypeDisplayName": "チャート", "embeddableApi.contextMenuTrigger.description": "新しいアクションがパネルのコンテキストメニューに追加されます", "embeddableApi.contextMenuTrigger.title": "コンテキストメニュー", - "embeddableApi.embeddableSavedObjectRegistry.keyAlreadyExistsError": "埋め込み可能タイプ\"{embeddableType}\"はすでにレジストリに存在します。", "embeddableApi.errors.embeddableFactoryNotFound": "{type} を読み込めません。Elasticsearch と Kibanaのデフォルトのディストリビューションを適切なライセンスでアップグレードしてください。", "embeddableApi.errors.paneldoesNotExist": "パネルが見つかりません", "embeddableApi.errors.panelIncompatibleError": "パネルAPIに互換性がありません", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 369522e39cd44..20e1de9fc8cc9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2799,7 +2799,6 @@ "domDragDrop.keyboardInstructionsReorder": "按空格键或 enter 键开始拖动。拖动时,请使用上下箭头键重新排列组中的项目,使用左右箭头键在组之外选择拖动目标。再次按空格键或 enter 键结束操作。", "embeddableApi.addPanel.managedPanelTooltip": "Elastic 将管理此面板。将其添加到仪表板会取消其与库的链接。", "embeddableApi.addPanel.noMatchingObjectsMessage": "未找到任何匹配对象。", - "embeddableApi.addPanel.savedObjectAddedToContainerSuccessMessageTitle": "{savedObjectName} 已添加", "embeddableApi.addPanel.Title": "从库中添加", "embeddableApi.attributeService.saveToLibraryError": "保存时出错。错误:{errorMessage}", "embeddableApi.cellValueTrigger.description": "操作在可视化上的单元格值选项中显示", @@ -2810,7 +2809,6 @@ "embeddableApi.compatibility.defaultTypeDisplayName": "图表", "embeddableApi.contextMenuTrigger.description": "会将一个新操作添加到该面板的上下文菜单", "embeddableApi.contextMenuTrigger.title": "上下文菜单", - "embeddableApi.embeddableSavedObjectRegistry.keyAlreadyExistsError": "注册表中已存在可嵌入对象类型 {embeddableType}。", "embeddableApi.errors.embeddableFactoryNotFound": "{type} 无法加载。请升级到具有适当许可的默认 Elasticsearch 和 Kibana 分发。", "embeddableApi.errors.paneldoesNotExist": "未找到面板", "embeddableApi.errors.panelIncompatibleError": "面板 API 不兼容",