diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts
index 1dce53b6c2a84..fb91b865097fa 100644
--- a/src/dev/storybook/aliases.ts
+++ b/src/dev/storybook/aliases.ts
@@ -20,6 +20,7 @@
export const storybookAliases = {
apm: 'x-pack/legacy/plugins/apm/scripts/storybook.js',
canvas: 'x-pack/legacy/plugins/canvas/scripts/storybook_new.js',
+ drilldowns: 'x-pack/plugins/drilldowns/scripts/storybook.js',
embeddable: 'src/plugins/embeddable/scripts/storybook.js',
infra: 'x-pack/legacy/plugins/infra/scripts/storybook.js',
siem: 'x-pack/legacy/plugins/siem/scripts/storybook.js',
diff --git a/src/plugins/embeddable/public/components/embeddable_panel/index.tsx b/src/plugins/embeddable/public/components/embeddable_panel/index.tsx
deleted file mode 100644
index 7089efa4bca88..0000000000000
--- a/src/plugins/embeddable/public/components/embeddable_panel/index.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { EuiPanel } from '@elastic/eui';
-import * as React from 'react';
-
-export const EmbeddablePanel = () => {
- return (
-
- Hello world
-
- );
-};
diff --git a/src/plugins/embeddable/public/components/embeddable_panel/__examples__/embeddable_panel.examples.tsx b/src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.examples.tsx
similarity index 53%
rename from src/plugins/embeddable/public/components/embeddable_panel/__examples__/embeddable_panel.examples.tsx
rename to src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.examples.tsx
index 7ec8848b8cebd..33724068a6ba8 100644
--- a/src/plugins/embeddable/public/components/embeddable_panel/__examples__/embeddable_panel.examples.tsx
+++ b/src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.examples.tsx
@@ -19,6 +19,35 @@
import * as React from 'react';
import { storiesOf } from '@storybook/react';
-import { EmbeddablePanel } from '..';
+import { action } from '@storybook/addon-actions';
+import { withKnobs, boolean } from '@storybook/addon-knobs';
+import { PanelOptionsMenu } from '..';
-storiesOf('components/EmbeddablePanel', module).add('default', () => );
+const euiContextDescriptors = {
+ id: 'mainMenu',
+ title: 'Options',
+ items: [
+ {
+ name: 'Inspect',
+ icon: 'inspect',
+ onClick: action('onClick(inspect)'),
+ },
+ {
+ name: 'Full screen',
+ icon: 'expand',
+ onClick: action('onClick(expand)'),
+ },
+ ],
+};
+
+storiesOf('components/PanelOptionsMenu', module)
+ .addDecorator(withKnobs)
+ .add('default', () => {
+ const isViewMode = boolean('isViewMode', false);
+
+ return (
+
+ );
+ });
diff --git a/src/plugins/embeddable/public/components/panel_options_menu/index.tsx b/src/plugins/embeddable/public/components/panel_options_menu/index.tsx
new file mode 100644
index 0000000000000..4a95027269587
--- /dev/null
+++ b/src/plugins/embeddable/public/components/panel_options_menu/index.tsx
@@ -0,0 +1,93 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { i18n } from '@kbn/i18n';
+import React, { useState, useEffect } from 'react';
+import {
+ EuiButtonIcon,
+ EuiContextMenu,
+ EuiContextMenuPanelDescriptor,
+ EuiPopover,
+} from '@elastic/eui';
+
+export interface PanelOptionsMenuProps {
+ panelDescriptor?: EuiContextMenuPanelDescriptor;
+ close?: boolean;
+ isViewMode?: boolean;
+ title?: string;
+}
+
+export const PanelOptionsMenu: React.FC = ({
+ panelDescriptor,
+ close,
+ isViewMode,
+ title,
+}) => {
+ const [open, setOpen] = useState(false);
+ useEffect(() => {
+ if (!close) setOpen(false);
+ }, [close]);
+
+ const handleContextMenuClick = () => {
+ setOpen(isOpen => !isOpen);
+ };
+
+ const handlePopoverClose = () => {
+ setOpen(false);
+ };
+
+ const enhancedAriaLabel = i18n.translate(
+ 'embeddableApi.panel.optionsMenu.panelOptionsButtonEnhancedAriaLabel',
+ {
+ defaultMessage: 'Panel options for {title}',
+ values: { title },
+ }
+ );
+ const ariaLabelWithoutTitle = i18n.translate(
+ 'embeddableApi.panel.optionsMenu.panelOptionsButtonAriaLabel',
+ {
+ defaultMessage: 'Panel options',
+ }
+ );
+
+ const button = (
+
+ );
+
+ return (
+
+
+
+ );
+};
diff --git a/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss b/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss
index 52a9ea594ff1d..9de20b73af0f8 100644
--- a/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss
+++ b/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss
@@ -100,7 +100,6 @@
}
}
-.embPanel__optionsMenuPopover[class*='-isOpen'],
.embPanel:hover {
.embPanel__optionsMenuButton {
opacity: 1;
diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json
index 9931d56a99a42..f22f7e98d3b8a 100644
--- a/x-pack/.i18nrc.json
+++ b/x-pack/.i18nrc.json
@@ -4,12 +4,14 @@
"xpack.actions": "plugins/actions",
"xpack.advancedUiActions": "plugins/advanced_ui_actions",
"xpack.alerting": "plugins/alerting",
- "xpack.triggersActionsUI": "plugins/triggers_actions_ui",
"xpack.apm": ["legacy/plugins/apm", "plugins/apm"],
"xpack.beatsManagement": "legacy/plugins/beats_management",
"xpack.canvas": "legacy/plugins/canvas",
"xpack.crossClusterReplication": "legacy/plugins/cross_cluster_replication",
"xpack.dashboardMode": "legacy/plugins/dashboard_mode",
+ "xpack.data": "plugins/data_enhanced",
+ "xpack.drilldowns": "plugins/drilldowns",
+ "xpack.endpoint": "plugins/endpoint",
"xpack.features": "plugins/features",
"xpack.fileUpload": "legacy/plugins/file_upload",
"xpack.graph": ["legacy/plugins/graph", "plugins/graph"],
@@ -17,30 +19,30 @@
"xpack.idxMgmt": "legacy/plugins/index_management",
"xpack.indexLifecycleMgmt": "legacy/plugins/index_lifecycle_management",
"xpack.infra": "plugins/infra",
- "xpack.data": "plugins/data_enhanced",
+ "xpack.ingestManager": "plugins/ingest_manager",
"xpack.lens": "legacy/plugins/lens",
- "xpack.licensing": "plugins/licensing",
"xpack.licenseMgmt": "legacy/plugins/license_management",
- "xpack.maps": "legacy/plugins/maps",
- "xpack.ml": "legacy/plugins/ml",
+ "xpack.licensing": "plugins/licensing",
"xpack.logstash": "legacy/plugins/logstash",
"xpack.main": "legacy/plugins/xpack_main",
+ "xpack.maps": "legacy/plugins/maps",
+ "xpack.ml": "legacy/plugins/ml",
"xpack.monitoring": "legacy/plugins/monitoring",
"xpack.remoteClusters": "plugins/remote_clusters",
"xpack.reporting": ["plugins/reporting", "legacy/plugins/reporting"],
"xpack.rollupJobs": "legacy/plugins/rollup",
"xpack.searchProfiler": "plugins/searchprofiler",
- "xpack.siem": "legacy/plugins/siem",
"xpack.security": ["legacy/plugins/security", "plugins/security"],
"xpack.server": "legacy/server",
+ "xpack.siem": "legacy/plugins/siem",
"xpack.snapshotRestore": "legacy/plugins/snapshot_restore",
"xpack.spaces": ["legacy/plugins/spaces", "plugins/spaces"],
"xpack.taskManager": "legacy/plugins/task_manager",
"xpack.transform": "legacy/plugins/transform",
+ "xpack.triggersActionsUI": "plugins/triggers_actions_ui",
"xpack.upgradeAssistant": "legacy/plugins/upgrade_assistant",
"xpack.uptime": "legacy/plugins/uptime",
- "xpack.watcher": "plugins/watcher",
- "xpack.endpoint": "plugins/endpoint"
+ "xpack.watcher": "plugins/watcher"
},
"translations": [
"plugins/translations/translations/zh-CN.json",
diff --git a/x-pack/plugins/drilldowns/README.md b/x-pack/plugins/drilldowns/README.md
new file mode 100644
index 0000000000000..701b6082d4985
--- /dev/null
+++ b/x-pack/plugins/drilldowns/README.md
@@ -0,0 +1,3 @@
+# Drilldowns
+
+Provides functionality to navigate between Kibana apps with context information.
diff --git a/x-pack/plugins/drilldowns/kibana.json b/x-pack/plugins/drilldowns/kibana.json
new file mode 100644
index 0000000000000..b951c7dc1fc87
--- /dev/null
+++ b/x-pack/plugins/drilldowns/kibana.json
@@ -0,0 +1,10 @@
+{
+ "id": "drilldowns",
+ "version": "kibana",
+ "server": false,
+ "ui": true,
+ "requiredPlugins": [
+ "uiActions",
+ "embeddable"
+ ]
+}
diff --git a/x-pack/plugins/drilldowns/public/actions/index.ts b/x-pack/plugins/drilldowns/public/actions/index.ts
new file mode 100644
index 0000000000000..c0ca7fac22049
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/actions/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './open_flyout_add_drilldown';
diff --git a/x-pack/plugins/drilldowns/public/actions/open_flyout_add_drilldown/index.tsx b/x-pack/plugins/drilldowns/public/actions/open_flyout_add_drilldown/index.tsx
new file mode 100644
index 0000000000000..06f134b10a4b7
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/actions/open_flyout_add_drilldown/index.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { CoreStart } from 'src/core/public';
+import { Action } from '../../../../../../src/plugins/ui_actions/public';
+import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public';
+import { IEmbeddable } from '../../../../../../src/plugins/embeddable/public';
+import { FormCreateDrilldown } from '../../components/form_create_drilldown';
+
+export const OPEN_FLYOUT_ADD_DRILLDOWN = 'OPEN_FLYOUT_ADD_DRILLDOWN';
+
+interface ActionContext {
+ embeddable: IEmbeddable;
+}
+
+export interface OpenFlyoutAddDrilldownParams {
+ overlays: () => Promise;
+}
+
+export class OpenFlyoutAddDrilldown implements Action {
+ public readonly type = OPEN_FLYOUT_ADD_DRILLDOWN;
+ public readonly id = OPEN_FLYOUT_ADD_DRILLDOWN;
+ public order = 100;
+
+ constructor(protected readonly params: OpenFlyoutAddDrilldownParams) {}
+
+ public getDisplayName() {
+ return i18n.translate('xpack.drilldowns.panel.openFlyoutAddDrilldown.displayName', {
+ defaultMessage: 'Add drilldown',
+ });
+ }
+
+ public getIconType() {
+ return 'empty';
+ }
+
+ public async isCompatible({ embeddable }: ActionContext) {
+ return true;
+ }
+
+ public async execute({ embeddable }: ActionContext) {
+ const overlays = await this.params.overlays();
+ overlays.openFlyout(toMountPoint());
+ }
+}
diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/__examples__/drilldown_hello_bar.examples.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/__examples__/drilldown_hello_bar.examples.tsx
new file mode 100644
index 0000000000000..afa82f5e74c16
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/__examples__/drilldown_hello_bar.examples.tsx
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as React from 'react';
+import { storiesOf } from '@storybook/react';
+import { DrilldownHelloBar } from '..';
+
+storiesOf('components/DrilldownHelloBar', module).add('default', () => {
+ return ;
+});
diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx
new file mode 100644
index 0000000000000..895a100df3ac5
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+export interface DrilldownHelloBarProps {
+ docsLink?: string;
+}
+
+export const DrilldownHelloBar: React.FC = ({ docsLink }) => {
+ return (
+
+
+ Drilldowns provide the ability to define a new behavior when interacting with a panel. You
+ can add multiple options or simply override the default filtering behavior.
+
+
View docs
+

+
+ );
+};
diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_picker/__examples__/drilldown_picker.examples.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_picker/__examples__/drilldown_picker.examples.tsx
new file mode 100644
index 0000000000000..dfdd9627ab5cd
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/drilldown_picker/__examples__/drilldown_picker.examples.tsx
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as React from 'react';
+import { storiesOf } from '@storybook/react';
+import { DrilldownPicker } from '..';
+
+storiesOf('components/DrilldownPicker', module).add('default', () => {
+ return ;
+});
diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx
new file mode 100644
index 0000000000000..3748fc666c81c
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+// eslint-disable-next-line
+export interface DrilldownPickerProps {}
+
+export const DrilldownPicker: React.FC = () => {
+ return (
+
+ );
+};
diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/__examples__/form_create_drilldown.examples.tsx b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/__examples__/form_create_drilldown.examples.tsx
new file mode 100644
index 0000000000000..34f6932b41dac
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/__examples__/form_create_drilldown.examples.tsx
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as React from 'react';
+import { storiesOf } from '@storybook/react';
+import { FormCreateDrilldown } from '..';
+
+storiesOf('components/FormCreateDrilldown', module).add('default', () => {
+ return ;
+});
diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts
new file mode 100644
index 0000000000000..922131ba4b901
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const txtNameOfDrilldown = i18n.translate(
+ 'xpack.drilldowns.components.form_create_drilldown.nameOfDrilldown',
+ {
+ defaultMessage: 'Name of drilldown',
+ }
+);
+
+export const txtUntitledDrilldown = i18n.translate(
+ 'xpack.drilldowns.components.form_create_drilldown.untitledDrilldown',
+ {
+ defaultMessage: 'Untitled drilldown',
+ }
+);
+
+export const txtDrilldownAction = i18n.translate(
+ 'xpack.drilldowns.components.form_create_drilldown.drilldownAction',
+ {
+ defaultMessage: 'Drilldown action',
+ }
+);
diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx
new file mode 100644
index 0000000000000..40cd4cf2b210b
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx
@@ -0,0 +1,30 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { EuiForm, EuiFormRow, EuiFieldText } from '@elastic/eui';
+import { DrilldownHelloBar } from '../drilldown_hello_bar';
+import { txtNameOfDrilldown, txtUntitledDrilldown, txtDrilldownAction } from './i18n';
+import { DrilldownPicker } from '../drilldown_picker';
+
+// eslint-disable-next-line
+export interface FormCreateDrilldownProps {}
+
+export const FormCreateDrilldown: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/drilldowns/public/index.ts b/x-pack/plugins/drilldowns/public/index.ts
new file mode 100644
index 0000000000000..63e7a12235462
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { DrilldownsPlugin } from './plugin';
+
+export {
+ DrilldownsSetupContract,
+ DrilldownsSetupDependencies,
+ DrilldownsStartContract,
+ DrilldownsStartDependencies,
+} from './plugin';
+
+export function plugin() {
+ return new DrilldownsPlugin();
+}
diff --git a/x-pack/plugins/drilldowns/public/mocks.ts b/x-pack/plugins/drilldowns/public/mocks.ts
new file mode 100644
index 0000000000000..bfade1674072a
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/mocks.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { DrilldownsSetupContract, DrilldownsStartContract } from '.';
+
+export type Setup = jest.Mocked;
+export type Start = jest.Mocked;
+
+const createSetupContract = (): Setup => {
+ const setupContract: Setup = {
+ registerDrilldown: jest.fn(),
+ };
+ return setupContract;
+};
+
+const createStartContract = (): Start => {
+ const startContract: Start = {};
+
+ return startContract;
+};
+
+export const bfetchPluginMock = {
+ createSetupContract,
+ createStartContract,
+};
diff --git a/x-pack/plugins/drilldowns/public/plugin.ts b/x-pack/plugins/drilldowns/public/plugin.ts
new file mode 100644
index 0000000000000..6c8555fa55a11
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/plugin.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { CoreStart, CoreSetup, Plugin } from 'src/core/public';
+import { UiActionsSetup, UiActionsStart } from '../../../../src/plugins/ui_actions/public';
+import { DrilldownService } from './service';
+
+export interface DrilldownsSetupDependencies {
+ uiActions: UiActionsSetup;
+}
+
+export interface DrilldownsStartDependencies {
+ uiActions: UiActionsStart;
+}
+
+export type DrilldownsSetupContract = Pick;
+
+// eslint-disable-next-line
+export interface DrilldownsStartContract {}
+
+export class DrilldownsPlugin
+ implements
+ Plugin<
+ DrilldownsSetupContract,
+ DrilldownsStartContract,
+ DrilldownsSetupDependencies,
+ DrilldownsStartDependencies
+ > {
+ private readonly service = new DrilldownService();
+
+ public setup(core: CoreSetup, plugins: DrilldownsSetupDependencies): DrilldownsSetupContract {
+ this.service.bootstrap(core, plugins);
+
+ return this.service;
+ }
+
+ public start(core: CoreStart, plugins: DrilldownsStartDependencies): DrilldownsStartContract {
+ return {};
+ }
+
+ public stop() {}
+}
diff --git a/x-pack/plugins/drilldowns/public/service/drilldown_service.ts b/x-pack/plugins/drilldowns/public/service/drilldown_service.ts
new file mode 100644
index 0000000000000..f22f452181648
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/service/drilldown_service.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { CoreSetup } from 'src/core/public';
+import { OpenFlyoutAddDrilldown } from '../actions/open_flyout_add_drilldown';
+import { DrilldownsSetupDependencies } from '../plugin';
+
+export class DrilldownService {
+ bootstrap(core: CoreSetup, { uiActions }: DrilldownsSetupDependencies) {
+ const actionOpenFlyoutAddDrilldown = new OpenFlyoutAddDrilldown({
+ overlays: async () => (await core.getStartServices())[0].overlays,
+ });
+
+ uiActions.registerAction(actionOpenFlyoutAddDrilldown);
+ uiActions.attachAction('CONTEXT_MENU_TRIGGER', actionOpenFlyoutAddDrilldown.id);
+ }
+
+ /**
+ * Convenience method to register a drilldown. (It should set-up all the
+ * necessary triggers and actions.)
+ */
+ registerDrilldown = (): void => {
+ throw new Error('not implemented');
+ };
+}
diff --git a/x-pack/plugins/drilldowns/public/service/index.ts b/x-pack/plugins/drilldowns/public/service/index.ts
new file mode 100644
index 0000000000000..44472b18a5317
--- /dev/null
+++ b/x-pack/plugins/drilldowns/public/service/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './drilldown_service';
diff --git a/x-pack/plugins/drilldowns/scripts/storybook.js b/x-pack/plugins/drilldowns/scripts/storybook.js
new file mode 100644
index 0000000000000..9b0f57746e584
--- /dev/null
+++ b/x-pack/plugins/drilldowns/scripts/storybook.js
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { join } from 'path';
+
+// eslint-disable-next-line
+require('@kbn/storybook').runStorybookCli({
+ name: 'drilldowns',
+ storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.examples.tsx')],
+});