diff --git a/examples/embeddable_examples/public/app/app.tsx b/examples/embeddable_examples/public/app/app.tsx index 72c5d4f11779a2..e29177b4749e78 100644 --- a/examples/embeddable_examples/public/app/app.tsx +++ b/examples/embeddable_examples/public/app/app.tsx @@ -21,9 +21,11 @@ import { EuiTabs, } from '@elastic/eui'; import { Overview } from './overview'; +import { RegisterEmbeddable } from './register_embeddable'; import { RenderExamples } from './render_examples'; const OVERVIEW_TAB_ID = 'overview'; +const REGISTER_EMBEDDABLE_TAB_ID = 'register'; const RENDER_TAB_ID = 'render'; const App = () => { @@ -38,6 +40,10 @@ const App = () => { return ; } + if (selectedTabId === REGISTER_EMBEDDABLE_TAB_ID) { + return ; + } + return ; } @@ -56,6 +62,12 @@ const App = () => { > Embeddables overview + onSelectedTabChanged(REGISTER_EMBEDDABLE_TAB_ID)} + isSelected={REGISTER_EMBEDDABLE_TAB_ID === selectedTabId} + > + Register new embeddable type + onSelectedTabChanged(RENDER_TAB_ID)} isSelected={RENDER_TAB_ID === selectedTabId} diff --git a/examples/embeddable_examples/public/app/register_embeddable.tsx b/examples/embeddable_examples/public/app/register_embeddable.tsx new file mode 100644 index 00000000000000..e9116a611d0ed1 --- /dev/null +++ b/examples/embeddable_examples/public/app/register_embeddable.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui'; +// @ts-ignore +import registerSearchEmbeddableSource from '!!raw-loader!../react_embeddables/search/register_search_embeddable'; +// @ts-ignore +import registerAttachActionSource from '!!raw-loader!../react_embeddables/search/register_add_search_panel_action'; + +export const RegisterEmbeddable = () => { + return ( + <> + +

+ This plugin registers several embeddable types with{' '} + registerReactEmbeddableFactory during plugin start. The code example + below shows Search embeddable registration. Notice how the embeddable factory is imported + asynchronously to limit initial page load size. +

+
+ + + {registerSearchEmbeddableSource} + + + + + +

+ Run the example embeddables by creating a dashboard, clicking Add panel button, + and then selecting Embeddable examples group. +

+

+ Add your own embeddables to Add panel menu by attaching an action to the{' '} + ADD_PANEL_TRIGGER trigger. Notice usage of grouping to + nest related panel types and avoid bloating Add panel menu. Please reach out to + @elastic/kibana-presentation team to coordinate menu updates. +

+
+ + + {registerAttachActionSource} + + + ); +}; diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index f143421f74b13a..3966861aecbda1 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -22,9 +22,9 @@ import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; import { registerCreateEuiMarkdownAction } from './react_embeddables/eui_markdown/create_eui_markdown_action'; import { registerCreateFieldListAction } from './react_embeddables/field_list/create_field_list_action'; import { registerAddSearchPanelAction } from './react_embeddables/search/register_add_search_panel_action'; +import { registerSearchEmbeddable } from './react_embeddables/search/register_search_embeddable'; import { EUI_MARKDOWN_ID } from './react_embeddables/eui_markdown/constants'; import { FIELD_LIST_ID } from './react_embeddables/field_list/constants'; -import { SEARCH_EMBEDDABLE_ID } from './react_embeddables/search/constants'; import { setupApp } from './app/setup_app'; export interface SetupDeps { @@ -65,12 +65,7 @@ export class EmbeddableExamplesPlugin implements Plugin { - const { getSearchEmbeddableFactory } = await import( - './react_embeddables/search/search_react_embeddable' - ); - return getSearchEmbeddableFactory(deps); - }); + registerSearchEmbeddable(deps); } public stop() {} diff --git a/examples/embeddable_examples/public/react_embeddables/add_panel_grouping.ts b/examples/embeddable_examples/public/react_embeddables/add_panel_grouping.ts new file mode 100644 index 00000000000000..2c043569d5cfbc --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/add_panel_grouping.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 or the Server + * Side Public License, v 1. + */ + +export const addPanelGrouping = { + id: 'embeddableExamples', + getDisplayName: () => 'Embeddable examples', +}; diff --git a/examples/embeddable_examples/public/react_embeddables/eui_markdown/create_eui_markdown_action.tsx b/examples/embeddable_examples/public/react_embeddables/eui_markdown/create_eui_markdown_action.tsx index 7aae7577dbb12e..21306a40372629 100644 --- a/examples/embeddable_examples/public/react_embeddables/eui_markdown/create_eui_markdown_action.tsx +++ b/examples/embeddable_examples/public/react_embeddables/eui_markdown/create_eui_markdown_action.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { apiCanAddNewPanel } from '@kbn/presentation-containers'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import { IncompatibleActionError, UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { addPanelGrouping } from '../add_panel_grouping'; import { ADD_EUI_MARKDOWN_ACTION_ID, EUI_MARKDOWN_ID } from './constants'; // ----------------------------------------------------------------------------- @@ -19,6 +20,7 @@ import { ADD_EUI_MARKDOWN_ACTION_ID, EUI_MARKDOWN_ID } from './constants'; export const registerCreateEuiMarkdownAction = (uiActions: UiActionsStart) => { uiActions.registerAction({ id: ADD_EUI_MARKDOWN_ACTION_ID, + grouping: [addPanelGrouping], getIconType: () => 'editorCodeBlock', isCompatible: async ({ embeddable }) => { return apiCanAddNewPanel(embeddable); diff --git a/examples/embeddable_examples/public/react_embeddables/field_list/create_field_list_action.tsx b/examples/embeddable_examples/public/react_embeddables/field_list/create_field_list_action.tsx index 1b860c81954f1a..8e02aa6e385e0b 100644 --- a/examples/embeddable_examples/public/react_embeddables/field_list/create_field_list_action.tsx +++ b/examples/embeddable_examples/public/react_embeddables/field_list/create_field_list_action.tsx @@ -12,10 +12,12 @@ import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; import { UiActionsPublicStart } from '@kbn/ui-actions-plugin/public/plugin'; import { ADD_FIELD_LIST_ACTION_ID, FIELD_LIST_ID } from './constants'; +import { addPanelGrouping } from '../add_panel_grouping'; export const registerCreateFieldListAction = (uiActions: UiActionsPublicStart) => { uiActions.registerAction({ id: ADD_FIELD_LIST_ACTION_ID, + grouping: [addPanelGrouping], getIconType: () => 'indexOpen', isCompatible: async ({ embeddable }) => { return apiCanAddNewPanel(embeddable); diff --git a/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx b/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx index 2466fa7be35330..391a9e3c370d41 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx +++ b/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx @@ -9,14 +9,14 @@ import { apiCanAddNewPanel } from '@kbn/presentation-containers'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import { IncompatibleActionError, UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { addPanelGrouping } from '../add_panel_grouping'; import { ADD_SEARCH_ACTION_ID, SEARCH_EMBEDDABLE_ID } from './constants'; export const registerAddSearchPanelAction = (uiActions: UiActionsStart) => { uiActions.registerAction({ id: ADD_SEARCH_ACTION_ID, - getDisplayName: () => 'Unified search example', - getDisplayNameTooltip: () => - 'Demonstrates how to use global filters, global time range, panel time range, and global query state in an embeddable', + grouping: [addPanelGrouping], + getDisplayName: () => 'Search example', getIconType: () => 'search', isCompatible: async ({ embeddable }) => { return apiCanAddNewPanel(embeddable); diff --git a/examples/embeddable_examples/public/react_embeddables/search/register_search_embeddable.ts b/examples/embeddable_examples/public/react_embeddables/search/register_search_embeddable.ts new file mode 100644 index 00000000000000..547437a61a2836 --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/search/register_search_embeddable.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 or the Server + * Side Public License, v 1. + */ + +import { registerReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; +import { SEARCH_EMBEDDABLE_ID } from './constants'; +import { Services } from './types'; + +export function registerSearchEmbeddable(services: Services) { + registerReactEmbeddableFactory(SEARCH_EMBEDDABLE_ID, async () => { + const { getSearchEmbeddableFactory } = await import('./search_react_embeddable'); + return getSearchEmbeddableFactory(services); + }); +}