From af76ea090254d43b6b8ee613888500a528a7a733 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Wed, 6 Jun 2018 13:30:57 -0400 Subject: [PATCH] Typescriptify dashboard panel actions (#19675) --- .../panel_actions/build_context_menu.js | 4 +- .../get_customize_panel_action.js | 40 +++-- .../panel_actions/get_edit_panel_action.js | 21 ++- .../panel_actions/get_remove_panel_action.js | 23 +-- .../get_toggle_expand_panel_action.js | 19 ++- .../dashboard_context_menu_panel.ts | 53 ++++++ .../dashboard_panel_action.js | 86 ---------- .../dashboard_panel_action.ts | 155 ++++++++++++++++++ ...js => dashboard_panel_actions_registry.ts} | 3 +- .../{index.js => index.ts} | 6 +- ...shboard_context_menu_panel.js => types.ts} | 30 ++-- src/ui/public/embeddable/index.ts | 1 + 12 files changed, 287 insertions(+), 154 deletions(-) create mode 100644 src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.ts delete mode 100644 src/ui/public/dashboard_panel_actions/dashboard_panel_action.js create mode 100644 src/ui/public/dashboard_panel_actions/dashboard_panel_action.ts rename src/ui/public/dashboard_panel_actions/{dashboard_panel_actions_registry.js => dashboard_panel_actions_registry.ts} (96%) rename src/ui/public/dashboard_panel_actions/{index.js => index.ts} (90%) rename src/ui/public/dashboard_panel_actions/{dashboard_context_menu_panel.js => types.ts} (62%) diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/build_context_menu.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/build_context_menu.js index 31128bfbc191..75d087ed7379 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/build_context_menu.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/build_context_menu.js @@ -120,8 +120,8 @@ function convertPanelActionToContextMenuItem({ action, containerState, embeddabl name: action.displayName, icon: action.icon, panel: _.get(action, 'childContextMenuPanel.id'), - onClick: () => action.onClick({ containerState, embeddable }), - disabled: action.isDisabled({ containerState, embeddable }), + onClick: () => action.onClick({ embeddable, containerState }), + disabled: action.isDisabled({ embeddable, containerState }), 'data-test-subj': `dashboardPanelAction-${action.id}`, }; } diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.js index e44dc61b5061..85692e71821d 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.js @@ -34,21 +34,27 @@ import { DashboardViewMode } from '../../../dashboard_view_mode'; * @return {DashboardPanelAction} */ export function getCustomizePanelAction({ onResetPanelTitle, onUpdatePanelTitle, title, closeContextMenu }) { - return new DashboardPanelAction({ - displayName: 'Customize panel', - id: 'customizePanel', - parentPanelId: 'mainMenu', - icon: , - isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT), - childContextMenuPanel: new DashboardContextMenuPanel({ - id: 'panelSubOptionsMenu', - title: 'Customize panel', - getContent: () => (), - }), - }); + return new DashboardPanelAction( + { + id: 'customizePanel', + displayName: 'Customize panel', + parentPanelId: 'mainMenu', + }, + { + icon: , + isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT), + childContextMenuPanel: new DashboardContextMenuPanel( + { + id: 'panelSubOptionsMenu', + title: 'Customize panel', + }, + { + getContent: () => (), + }), + }); } diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.js index 62c8398ab147..d1746a843a6b 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.js @@ -31,13 +31,16 @@ import { DashboardViewMode } from '../../../dashboard_view_mode'; * @return {DashboardPanelAction} */ export function getEditPanelAction() { - return new DashboardPanelAction({ - displayName: 'Edit visualization', - id: 'editPanel', - icon: , - parentPanelId: 'mainMenu', - onClick: ({ embeddable }) => { window.location = embeddable.metadata.editUrl; }, - isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT), - isDisabled: ({ embeddable }) => (!embeddable || !embeddable.metadata || !embeddable.metadata.editUrl), - }); + return new DashboardPanelAction( + { + displayName: 'Edit visualization', + id: 'editPanel', + parentPanelId: 'mainMenu', + }, + { + icon: , + onClick: ({ embeddable }) => { window.location = embeddable.metadata.editUrl; }, + isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT), + isDisabled: ({ embeddable }) => (!embeddable || !embeddable.metadata || !embeddable.metadata.editUrl), + }); } diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.js index 1401fb2a6853..dd9856cd5201 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.js @@ -31,14 +31,17 @@ import { DashboardViewMode } from '../../../dashboard_view_mode'; * @return {DashboardPanelAction} */ export function getRemovePanelAction(onDeletePanel) { - return new DashboardPanelAction({ - displayName: 'Delete from dashboard', - id: 'deletePanel', - parentPanelId: 'mainMenu', - icon: , - isVisible: ({ containerState }) => ( - containerState.viewMode === DashboardViewMode.EDIT && !containerState.isPanelExpanded - ), - onClick: onDeletePanel, - }); + return new DashboardPanelAction( + { + displayName: 'Delete from dashboard', + id: 'deletePanel', + parentPanelId: 'mainMenu', + }, + { + icon: , + isVisible: ({ containerState }) => ( + containerState.viewMode === DashboardViewMode.EDIT && !containerState.isPanelExpanded + ), + onClick: onDeletePanel, + }); } diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.js index 9621a19b9c0a..8cf1606c296a 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.js @@ -31,12 +31,15 @@ import { DashboardPanelAction } from 'ui/dashboard_panel_actions'; * @return {DashboardPanelAction} */ export function getToggleExpandPanelAction({ isExpanded, toggleExpandedPanel }) { - return new DashboardPanelAction({ - displayName: isExpanded ? 'Minimize' : 'Full screen', - id: 'togglePanel', - parentPanelId: 'mainMenu', - // TODO: Update to minimize icon when https://github.com/elastic/eui/issues/837 is complete. - icon: , - onClick: toggleExpandedPanel, - }); + return new DashboardPanelAction( + { + displayName: isExpanded ? 'Minimize' : 'Full screen', + id: 'togglePanel', + parentPanelId: 'mainMenu', + }, + { + // TODO: Update to minimize icon when https://github.com/elastic/eui/issues/837 is complete. + icon: , + onClick: toggleExpandedPanel, + }); } diff --git a/src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.ts b/src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.ts new file mode 100644 index 000000000000..ee3e0969cf82 --- /dev/null +++ b/src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.ts @@ -0,0 +1,53 @@ +/* + * 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 { PanelActionAPI } from './types'; + +interface DashboardContextMenuPanelOptions { + getContent?: (panelActionAPI: PanelActionAPI) => HTMLElement | undefined; +} + +interface DashboardContextMenuPanelConfig { + id: string; + title: string; +} + +export abstract class DashboardContextMenuPanel { + public readonly id: string; + public readonly title: string; + + constructor( + config: DashboardContextMenuPanelConfig, + options: DashboardContextMenuPanelOptions = {} + ) { + this.id = config.id; + this.title = config.title; + + if (options.getContent) { + this.getContent = options.getContent; + } + } + + /** + * Optional, could be composed of actions instead of content. + */ + public getContent(panelActionAPI: PanelActionAPI): HTMLElement | undefined { + return; + } +} diff --git a/src/ui/public/dashboard_panel_actions/dashboard_panel_action.js b/src/ui/public/dashboard_panel_actions/dashboard_panel_action.js deleted file mode 100644 index 15f3178d1eda..000000000000 --- a/src/ui/public/dashboard_panel_actions/dashboard_panel_action.js +++ /dev/null @@ -1,86 +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. - */ - -export class DashboardPanelAction { - /** - * - * @param {string} id - * @param {string} displayName - * @param {function} onClick - * @param {DashboardContextMenuPanel} childContextMenuPanel - optional child panel to open when clicked. - * @param {function} isDisabled - optionally set a custom disabled function - * @param {function} isVisible - optionally set a custom isVisible function - * @param {string} parentPanelId - set if this action belongs on a nested child panel - * @param {Element} icon - */ - constructor( - { - id, - displayName, - onClick, - childContextMenuPanel, - isDisabled, - isVisible, - parentPanelId, - icon, - } = {}) { - this.id = id; - this.icon = icon; - this.displayName = displayName; - this.childContextMenuPanel = childContextMenuPanel; - this.parentPanelId = parentPanelId; - - if (onClick) { - this.onClick = onClick; - } - - if (isDisabled) { - this.isDisabled = isDisabled; - } - - if (isVisible) { - this.isVisible = isVisible; - } - } - - /** - * @param {Embeddable} embeddable - * @param ContainerState} containerState - */ - onClick(/*{ embeddable, containerState }*/) {} - - /** - * Defaults to always visible. - * @param {Embeddable} embeddable - * @param ContainerState} containerState - * @return {boolean} - */ - isVisible(/*{ embeddable, containerState }*/) { - return true; - } - - /** - * Defaults to always enabled. - * @param {Embeddable} embeddable - * @param {ContainerState} containerState - */ - isDisabled(/*{ embeddable, containerState }*/) { - return false; - } -} diff --git a/src/ui/public/dashboard_panel_actions/dashboard_panel_action.ts b/src/ui/public/dashboard_panel_actions/dashboard_panel_action.ts new file mode 100644 index 000000000000..bb25299b0269 --- /dev/null +++ b/src/ui/public/dashboard_panel_actions/dashboard_panel_action.ts @@ -0,0 +1,155 @@ +/* + * 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 { DashboardContextMenuPanel } from './dashboard_context_menu_panel'; +import { PanelActionAPI } from './types'; + +interface DashboardPanelActionOptions { + /** + * An optional action to take when the action is clicked on. Either this or childContextMenuPanel should be + * given. + */ + onClick?: (actionAPI: PanelActionAPI) => void; + + /** + * An optional child context menu to display when the action is clicked. + */ + childContextMenuPanel?: DashboardContextMenuPanel; + + /** + * Whether this action should be disabled based on the parameters given. + * @param {PanelActionAPI} panelActionAPI + * @return {boolean} + */ + isDisabled?: (actionAPI: PanelActionAPI) => boolean; + + /** + * Whether this action should be visible based on the parameters given. + * @param {PanelActionAPI} panelActionAPI + * @return {boolean} + */ + isVisible?: (panelActionAPI: PanelActionAPI) => boolean; + + /** + * Determines which DashboardContextMenuPanel this action is displayed on. + */ + parentPanelId?: string; + + /** + * Optional icon to display to the left of the action. + */ + icon?: Node; +} + +interface DashboardPanelActionsConfig { + id: string; + + /** + * Display name of the action in the menu + */ + displayName: string; + + /** + * Determines which DashboardContextMenuPanel this action is displayed on. + */ + parentPanelId: string; +} + +export abstract class DashboardPanelAction { + public readonly id: string; + + /** + * Optional icon to display to the left of the action. + */ + public readonly icon?: Node; + + /** + * Display name of the action in the menu + */ + public readonly displayName: string; + + /** + * Optional child context menu to open when the action is clicked. + */ + public readonly childContextMenuPanel?: DashboardContextMenuPanel; + + /** + * Determines which DashboardContextMenuPanel this action is displayed on. + */ + public readonly parentPanelId: string; + + /** + * + * @param {string} config.id + * @param {string} config.displayName + * @param {string} config.parentPanelId - set if this action belongs on a nested child panel + * @param {function} options.onClick + * @param {DashboardContextMenuPanel} options.childContextMenuPanel - optional child panel to open when clicked. + * @param {function} options.isDisabled - optionally set a custom disabled function + * @param {function} options.isVisible - optionally set a custom isVisible function + * @param {Element} options.icon + */ + protected constructor( + config: DashboardPanelActionsConfig, + options: DashboardPanelActionOptions = {} + ) { + this.id = config.id; + this.displayName = config.displayName; + this.parentPanelId = config.parentPanelId; + + this.icon = options.icon; + this.childContextMenuPanel = options.childContextMenuPanel; + + if (options.onClick) { + this.onClick = options.onClick; + } + + if (options.isDisabled) { + this.isDisabled = options.isDisabled; + } + + if (options.isVisible) { + this.isVisible = options.isVisible; + } + } + + /** + * @param {PanelActionAPI} panelActionAPI + */ + public onClick(panelActionAPI: PanelActionAPI): void { + return; + } + + /** + * Whether this action should be visible based on the parameters given. Defaults to always visible. + * @param {PanelActionAPI} panelActionAPI + * @return {boolean} + */ + public isVisible(panelActionAPI: PanelActionAPI): boolean { + return true; + } + + /** + * Whether this action should be disabled based on the parameters given. Defaults to always enabled. + * @param {PanelActionAPI} panelActionAPI + */ + public isDisabled(panelActionAPI: PanelActionAPI): boolean { + return false; + } +} diff --git a/src/ui/public/dashboard_panel_actions/dashboard_panel_actions_registry.js b/src/ui/public/dashboard_panel_actions/dashboard_panel_actions_registry.ts similarity index 96% rename from src/ui/public/dashboard_panel_actions/dashboard_panel_actions_registry.js rename to src/ui/public/dashboard_panel_actions/dashboard_panel_actions_registry.ts index 4d3c017b3cf0..eb51f6f4a313 100644 --- a/src/ui/public/dashboard_panel_actions/dashboard_panel_actions_registry.js +++ b/src/ui/public/dashboard_panel_actions/dashboard_panel_actions_registry.ts @@ -17,9 +17,10 @@ * under the License. */ +// @ts-ignore: implicit any for JS file import { uiRegistry } from 'ui/registry/_registry'; export const DashboardPanelActionsRegistryProvider = uiRegistry({ - name: 'dashboardPanelActions', index: ['name'], + name: 'dashboardPanelActions', }); diff --git a/src/ui/public/dashboard_panel_actions/index.js b/src/ui/public/dashboard_panel_actions/index.ts similarity index 90% rename from src/ui/public/dashboard_panel_actions/index.js rename to src/ui/public/dashboard_panel_actions/index.ts index 759ece6ec56a..a11538441a43 100644 --- a/src/ui/public/dashboard_panel_actions/index.js +++ b/src/ui/public/dashboard_panel_actions/index.ts @@ -17,6 +17,8 @@ * under the License. */ -export { DashboardPanelAction } from './dashboard_panel_action'; -export { DashboardPanelActionsRegistryProvider } from './dashboard_panel_actions_registry'; export { DashboardContextMenuPanel } from './dashboard_context_menu_panel'; +export { DashboardPanelAction } from './dashboard_panel_action'; +export { + DashboardPanelActionsRegistryProvider, +} from './dashboard_panel_actions_registry'; diff --git a/src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.js b/src/ui/public/dashboard_panel_actions/types.ts similarity index 62% rename from src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.js rename to src/ui/public/dashboard_panel_actions/types.ts index 03537d846f3b..7bd8b6e44282 100644 --- a/src/ui/public/dashboard_panel_actions/dashboard_context_menu_panel.js +++ b/src/ui/public/dashboard_panel_actions/types.ts @@ -17,27 +17,19 @@ * under the License. */ -export class DashboardContextMenuPanel { - /** - * @param {string} id - * @param {string} title - * @param {function} getContent - */ - constructor({ id, title, getContent }) { - this.id = id; - this.title = title; +import { ContainerState, Embeddable } from 'ui/embeddable'; - if (getContent) { - this.getContent = getContent; - } - } +/** + * Exposes information about the current state of the panel and the embeddable rendered internally. + */ +export interface PanelActionAPI { + /** + * The embeddable that resides inside this action. + */ + embeddable: Embeddable; /** - * Optional, could be composed of actions instead of content. - * @param {Embeddable} embeddable - * @param {ContainerState} containerState + * Information about the current state of the panel and dashboard. */ - getContent(/*{ embeddable, containerState }*/) { - return null; - } + containerState: ContainerState; } diff --git a/src/ui/public/embeddable/index.ts b/src/ui/public/embeddable/index.ts index 5517a14efede..408a0d5127d1 100644 --- a/src/ui/public/embeddable/index.ts +++ b/src/ui/public/embeddable/index.ts @@ -22,3 +22,4 @@ export * from './embeddable'; export { EmbeddableFactoriesRegistryProvider, } from './embeddable_factories_registry'; +export { ContainerState } from './types';