Typescriptify dashboard panel actions (#19675)

This commit is contained in:
Stacey Gammon 2018-06-06 13:30:57 -04:00 committed by GitHub
parent 831b9f83fd
commit af76ea0902
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 287 additions and 154 deletions

View file

@ -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}`,
};
}

View file

@ -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: <EuiIcon type="pencil" />,
isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT),
childContextMenuPanel: new DashboardContextMenuPanel({
id: 'panelSubOptionsMenu',
title: 'Customize panel',
getContent: () => (<PanelOptionsMenuForm
onReset={onResetPanelTitle}
onUpdatePanelTitle={onUpdatePanelTitle}
title={title}
onClose={closeContextMenu}
/>),
}),
});
return new DashboardPanelAction(
{
id: 'customizePanel',
displayName: 'Customize panel',
parentPanelId: 'mainMenu',
},
{
icon: <EuiIcon type="pencil" />,
isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT),
childContextMenuPanel: new DashboardContextMenuPanel(
{
id: 'panelSubOptionsMenu',
title: 'Customize panel',
},
{
getContent: () => (<PanelOptionsMenuForm
onReset={onResetPanelTitle}
onUpdatePanelTitle={onUpdatePanelTitle}
title={title}
onClose={closeContextMenu}
/>),
}),
});
}

View file

@ -31,13 +31,16 @@ import { DashboardViewMode } from '../../../dashboard_view_mode';
* @return {DashboardPanelAction}
*/
export function getEditPanelAction() {
return new DashboardPanelAction({
displayName: 'Edit visualization',
id: 'editPanel',
icon: <EuiIcon type="pencil" />,
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: <EuiIcon type="pencil" />,
onClick: ({ embeddable }) => { window.location = embeddable.metadata.editUrl; },
isVisible: ({ containerState }) => (containerState.viewMode === DashboardViewMode.EDIT),
isDisabled: ({ embeddable }) => (!embeddable || !embeddable.metadata || !embeddable.metadata.editUrl),
});
}

View file

@ -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: <EuiIcon type="trash" />,
isVisible: ({ containerState }) => (
containerState.viewMode === DashboardViewMode.EDIT && !containerState.isPanelExpanded
),
onClick: onDeletePanel,
});
return new DashboardPanelAction(
{
displayName: 'Delete from dashboard',
id: 'deletePanel',
parentPanelId: 'mainMenu',
},
{
icon: <EuiIcon type="trash" />,
isVisible: ({ containerState }) => (
containerState.viewMode === DashboardViewMode.EDIT && !containerState.isPanelExpanded
),
onClick: onDeletePanel,
});
}

View file

@ -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: <EuiIcon type={isExpanded ? 'expand' : 'expand'} />,
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: <EuiIcon type={isExpanded ? 'expand' : 'expand'} />,
onClick: toggleExpandedPanel,
});
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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',
});

View file

@ -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';

View file

@ -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;
}

View file

@ -22,3 +22,4 @@ export * from './embeddable';
export {
EmbeddableFactoriesRegistryProvider,
} from './embeddable_factories_registry';
export { ContainerState } from './types';