From 23c6106065fd824a6bf59ccf913117462fb65668 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Thu, 16 Nov 2017 15:56:29 -0500 Subject: [PATCH] Add a feature for custom panel titles (#14831) (#15004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a feature for custom panel titles * Add tests and put back data-test-subjs * sync with master and add padding to form * UI/UX cleanup - add enter on close functionality - make reset title a link instead of a button - Push css to visualizations instead of the panel. This means background colors will be flush to the panel. Override for tile maps which apparently need it (yet region maps don’t for some reason??) * Fix refactor miss from merge * whoops, put block display back to make link fall to bottom * Undo accidental delete visualization name change * Color top pop over arrow correctly * Use naming Options and Customize Panel * update jest snapshot * Use custom panels for data-title attributes --- .../kibana/public/dashboard/actions/panels.js | 9 ++ .../dashboard_panel.test.js.snap | 2 +- .../dashboard/panel/dashboard_panel.test.js | 6 +- .../panel/panel_header/delete_menu_item.js | 27 ------ .../panel/panel_header/edit_menu_item.js | 27 ------ .../expand_or_collapse_menu_item.js | 28 ------ .../panel/panel_header/panel_header.js | 13 ++- .../panel_header/panel_header_container.js | 7 +- .../panel_header_container.test.js | 59 ++++++++++++ .../panel/panel_header/panel_options_menu.js | 93 +++++++++++++++---- .../panel_options_menu_container.js | 15 ++- .../panel_header/panel_options_menu_form.js | 53 +++++++++++ .../public/dashboard/reducers/panels.js | 29 ++++++ .../kibana/public/dashboard/styles/index.less | 28 ++++++ .../embeddable/search_embeddable_factory.js | 1 + .../discover/embeddable/search_template.html | 2 +- .../visualize_embeddable_factory.js | 1 + .../embeddable/visualize_template.html | 2 +- .../tile_map/public/styles/_tilemap.less | 8 ++ src/ui/public/visualize/visualize.less | 1 + ui_framework/src/test/index.js | 3 + ui_framework/src/test/test_subjects.js | 8 ++ 22 files changed, 310 insertions(+), 112 deletions(-) delete mode 100644 src/core_plugins/kibana/public/dashboard/panel/panel_header/delete_menu_item.js delete mode 100644 src/core_plugins/kibana/public/dashboard/panel/panel_header/edit_menu_item.js delete mode 100644 src/core_plugins/kibana/public/dashboard/panel/panel_header/expand_or_collapse_menu_item.js create mode 100644 src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.js create mode 100644 src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_form.js create mode 100644 ui_framework/src/test/test_subjects.js diff --git a/src/core_plugins/kibana/public/dashboard/actions/panels.js b/src/core_plugins/kibana/public/dashboard/actions/panels.js index 2059d36d17fb..b050fc736209 100644 --- a/src/core_plugins/kibana/public/dashboard/actions/panels.js +++ b/src/core_plugins/kibana/public/dashboard/actions/panels.js @@ -3,6 +3,15 @@ import { createAction } from 'redux-actions'; export const deletePanel = createAction('DELETE_PANEL'); export const updatePanel = createAction('UPDATE_PANEL'); +export const resetPanelTitle = createAction('RESET_PANEl_TITLE'); +export const setPanelTitle = createAction('SET_PANEl_TITLE', + /** + * @param title {string} + * @param panelIndex {string} + */ + (title, panelIndex) => ({ title, panelIndex }) +); + function panelArrayToMap(panels) { const panelsMap = {}; diff --git a/src/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.js.snap b/src/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.js.snap index 15fe51b94b50..4df54e84073a 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.js.snap +++ b/src/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.js.snap @@ -21,7 +21,7 @@ exports[`DashboardPanel matches snapshot 1`] = ` class="kuiMicroButtonGroup" >
{ store.dispatch(updateViewMode(DashboardViewMode.EDIT)); + store.dispatch(setPanels([{ panelIndex: 'foo1' }])); }); test('DashboardPanel matches snapshot', () => { diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/delete_menu_item.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/delete_menu_item.js deleted file mode 100644 index 6ff74f516542..000000000000 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/delete_menu_item.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { - KuiContextMenuItem, -} from 'ui_framework/components'; - -export function DeleteMenuItem({ onDeletePanel }) { - return ( - - ); -} - -DeleteMenuItem.propTypes = { - onDeletePanel: PropTypes.func.isRequired -}; diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/edit_menu_item.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/edit_menu_item.js deleted file mode 100644 index b93834e64647..000000000000 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/edit_menu_item.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { - KuiContextMenuItem, -} from 'ui_framework/components'; - -export function EditMenuItem({ onEditPanel }) { - return ( - - ); -} - -EditMenuItem.propTypes = { - onEditPanel: PropTypes.func.isRequired -}; diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/expand_or_collapse_menu_item.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/expand_or_collapse_menu_item.js deleted file mode 100644 index 7551b25e1458..000000000000 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/expand_or_collapse_menu_item.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { - KuiContextMenuItem, -} from 'ui_framework/components'; - -export function ExpandOrCollapseMenuItem({ onToggleExpand, isExpanded }) { - return ( - - ); -} - -ExpandOrCollapseMenuItem.propTypes = { - onToggleExpand: PropTypes.func.isRequired, - isExpanded: PropTypes.bool.isRequired, -}; diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.js index ac924f8f7c96..2d15633c69e9 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.js @@ -1,7 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; -export function PanelHeader({ title, actions }) { +export function PanelHeader({ title, actions, isViewOnlyMode }) { + if (isViewOnlyMode && !title) { + return ( +
+
+ {actions} +
+
+ ); + } + return (
{ const embeddable = getEmbeddable(dashboard, panelId); + const panel = getPanel(dashboard, panelId); + const embeddableTitle = embeddable ? embeddable.title : ''; return { - title: embeddable ? getEmbeddableTitle(dashboard, panelId) : '', + title: panel.title === undefined ? embeddableTitle : panel.title, isExpanded: getMaximizedPanelId(dashboard) === panelId, isViewOnlyMode: getFullScreenMode(dashboard) || getViewMode(dashboard) === DashboardViewMode.VIEW, }; @@ -57,6 +59,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { return { title, actions, + isViewOnlyMode, }; }; diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.js new file mode 100644 index 000000000000..0ff43bcc6541 --- /dev/null +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import _ from 'lodash'; +import { mount } from 'enzyme'; + +import { PanelHeaderContainer } from './panel_header_container'; +import { DashboardViewMode } from '../../dashboard_view_mode'; +import { store } from '../../../store'; +import { + updateViewMode, + setPanels, + setPanelTitle, + resetPanelTitle, + embeddableRenderFinished, +} from '../../actions'; +import { getEmbeddableFactoryMock } from '../../__tests__/get_embeddable_factories_mock'; +import { + TestSubjects, +} from 'ui_framework/src/test'; + +function getProps(props = {}) { + const defaultTestProps = { + panelId: 'foo1', + embeddableFactory: getEmbeddableFactoryMock(), + }; + return _.defaultsDeep(props, defaultTestProps); +} + +let component; + +beforeAll(() => { + store.dispatch(updateViewMode(DashboardViewMode.EDIT)); + store.dispatch(setPanels([{ panelIndex: 'foo1' }])); + store.dispatch(embeddableRenderFinished('foo1', { title: 'my embeddable title', editUrl: 'editme' })); +}); + +afterAll(() => { + component.unmount(); +}); + +test('Panel header shows embeddable title when nothing is set on the panel', () => { + component = mount(); + expect(TestSubjects.getText(component, 'dashboardPanelTitle')).toBe('my embeddable title'); +}); + +test('Panel header shows panel title when it is set on the panel', () => { + store.dispatch(setPanelTitle('my custom panel title', 'foo1')); + expect(TestSubjects.getText(component, 'dashboardPanelTitle')).toBe('my custom panel title'); +}); + +test('Panel header shows no panel title when it is set to an empty string on the panel', () => { + store.dispatch(setPanelTitle('', 'foo1')); + expect(TestSubjects.getText(component, 'dashboardPanelTitle')).toBe(''); +}); + +test('Panel header shows embeddable title when the panel title is reset', () => { + store.dispatch(resetPanelTitle('foo1')); + expect(TestSubjects.getText(component, 'dashboardPanelTitle')).toBe('my embeddable title'); +}); diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.js b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.js index 2b24d061b162..074c3e83883d 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.js @@ -2,13 +2,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import { KuiPopover, - KuiContextMenuPanel, + KuiContextMenu, KuiKeyboardAccessible, } from 'ui_framework/components'; -import { EditMenuItem } from './edit_menu_item'; -import { DeleteMenuItem } from './delete_menu_item'; -import { ExpandOrCollapseMenuItem } from './expand_or_collapse_menu_item'; +import { PanelOptionsMenuForm } from './panel_options_menu_form'; export class PanelOptionsMenu extends React.Component { state = { @@ -35,23 +33,74 @@ export class PanelOptionsMenu extends React.Component { this.props.toggleExpandedPanel(); }; - renderItems() { - const items = [ - , - + buildMainMenuPanel() { + const { isExpanded } = this.props; + const mainPanelMenuItems = [ + { + name: 'Edit visualization', + 'data-test-subj': 'dashboardPanelEditLink', + icon: