diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index d1e4c9d2d2a0c0..f1e1f20de1ce66 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -754,7 +754,7 @@ export class DashboardAppController { * When de-angularizing this code, please call the underlaying action function * directly and not via the top nav object. **/ - navActions[TopNavIds.ADD](); + navActions[TopNavIds.ADD_EXISTING](); }; $scope.enterEditMode = () => { dashboardStateManager.setFullScreenMode(false); @@ -847,7 +847,8 @@ export class DashboardAppController { showCloneModal(onClone, currentTitle); }; - navActions[TopNavIds.ADD] = () => { + + navActions[TopNavIds.ADD_EXISTING] = () => { if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) { openAddPanelFlyout({ embeddable: dashboardContainer, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/get_top_nav_config.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/get_top_nav_config.ts index 7188fab19d6f2f..7a3cb4b7dad56c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/get_top_nav_config.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/get_top_nav_config.ts @@ -48,9 +48,10 @@ export function getTopNavConfig( ]; case ViewMode.EDIT: return [ + getCreateNewConfig(actions[TopNavIds.VISUALIZE]), getSaveConfig(actions[TopNavIds.SAVE]), getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]), - getAddConfig(actions[TopNavIds.ADD]), + getAddConfig(actions[TopNavIds.ADD_EXISTING]), getOptionsConfig(actions[TopNavIds.OPTIONS]), getShareConfig(actions[TopNavIds.SHARE]), ]; @@ -161,6 +162,25 @@ function getAddConfig(action: NavAction) { }; } +/** + * @returns {kbnTopNavConfig} + */ +function getCreateNewConfig(action: NavAction) { + return { + emphasize: true, + iconType: 'plusInCircle', + id: 'addNew', + label: i18n.translate('kbn.dashboard.topNave.addNewButtonAriaLabel', { + defaultMessage: 'Create new', + }), + description: i18n.translate('kbn.dashboard.topNave.addNewConfigDescription', { + defaultMessage: 'Create a new panel on this dashboard', + }), + testId: 'dashboardAddNewPanelButton', + run: action, + }; +} + /** * @returns {kbnTopNavConfig} */ diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/top_nav_ids.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/top_nav_ids.ts index c67d6891c18e70..748bfaaab61417 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/top_nav_ids.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/top_nav_ids.ts @@ -18,7 +18,6 @@ */ export const TopNavIds = { - ADD: 'add', SHARE: 'share', OPTIONS: 'options', SAVE: 'save', @@ -27,4 +26,5 @@ export const TopNavIds = { CLONE: 'clone', FULL_SCREEN: 'fullScreenMode', VISUALIZE: 'visualize', + ADD_EXISTING: 'addExisting', }; diff --git a/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap b/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap new file mode 100644 index 00000000000000..0d54d5d3e9c4a1 --- /dev/null +++ b/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TopNavMenu Should render emphasized item which should be clickable 1`] = ` + + Test + +`; diff --git a/src/plugins/navigation/public/top_nav_menu/_index.scss b/src/plugins/navigation/public/top_nav_menu/_index.scss index 4a0e6af3f7f701..5befe4789dd6ca 100644 --- a/src/plugins/navigation/public/top_nav_menu/_index.scss +++ b/src/plugins/navigation/public/top_nav_menu/_index.scss @@ -1,7 +1,11 @@ .kbnTopNavMenu__wrapper { z-index: 5; - .kbnTopNavMenu { - padding: $euiSizeS 0px $euiSizeXS; + .kbnTopNavMenu { + padding: $euiSizeS 0; + + .kbnTopNavItemEmphasized { + padding: 0 $euiSizeS; + } } } diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index 80d1a53cd417f5..14ad40f13e3883 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -46,7 +46,11 @@ export function TopNavMenu(props: TopNavMenuProps) { if (!config) return; return config.map((menuItem: TopNavMenuData, i: number) => { return ( - + ); @@ -66,6 +70,7 @@ export function TopNavMenu(props: TopNavMenuProps) { void; export interface TopNavMenuData { @@ -28,6 +30,9 @@ export interface TopNavMenuData { className?: string; disableButton?: boolean | (() => boolean); tooltip?: string | (() => string); + emphasize?: boolean; + iconType?: string; + iconSide?: ButtonIconSide; } export interface RegisteredTopNavMenuData extends TopNavMenuData { diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.test.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.test.tsx index 4816ef3c958694..9ba58379c5ce15 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.test.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.test.tsx @@ -23,6 +23,15 @@ import { TopNavMenuData } from './top_nav_menu_data'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; describe('TopNavMenu', () => { + const ensureMenuItemDisabled = (data: TopNavMenuData) => { + const component = shallowWithIntl(); + expect(component.prop('isDisabled')).toEqual(true); + + const event = { currentTarget: { value: 'a' } }; + component.simulate('click', event); + expect(data.run).toHaveBeenCalledTimes(0); + }; + it('Should render and click an item', () => { const data: TopNavMenuData = { id: 'test', @@ -60,35 +69,62 @@ describe('TopNavMenu', () => { expect(data.run).toHaveBeenCalled(); }); - it('Should render disabled item and it shouldnt be clickable', () => { + it('Should render emphasized item which should be clickable', () => { const data: TopNavMenuData = { id: 'test', label: 'test', - disableButton: true, + iconType: 'beaker', + iconSide: 'right', + emphasize: true, run: jest.fn(), }; const component = shallowWithIntl(); - expect(component.prop('isDisabled')).toEqual(true); - const event = { currentTarget: { value: 'a' } }; component.simulate('click', event); - expect(data.run).toHaveBeenCalledTimes(0); + expect(data.run).toHaveBeenCalledTimes(1); + expect(component).toMatchSnapshot(); + }); + + it('Should render disabled item and it shouldnt be clickable', () => { + ensureMenuItemDisabled({ + id: 'test', + label: 'test', + disableButton: true, + run: jest.fn(), + }); }); it('Should render item with disable function and it shouldnt be clickable', () => { - const data: TopNavMenuData = { + ensureMenuItemDisabled({ id: 'test', label: 'test', disableButton: () => true, run: jest.fn(), - }; + }); + }); - const component = shallowWithIntl(); - expect(component.prop('isDisabled')).toEqual(true); + it('Should render disabled emphasized item which shouldnt be clickable', () => { + ensureMenuItemDisabled({ + id: 'test', + label: 'test', + iconType: 'beaker', + iconSide: 'right', + emphasize: true, + disableButton: true, + run: jest.fn(), + }); + }); - const event = { currentTarget: { value: 'a' } }; - component.simulate('click', event); - expect(data.run).toHaveBeenCalledTimes(0); + it('Should render emphasized item with disable function and it shouldnt be clickable', () => { + ensureMenuItemDisabled({ + id: 'test', + label: 'test', + iconType: 'beaker', + iconSide: 'right', + emphasize: true, + disableButton: () => true, + run: jest.fn(), + }); }); }); diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx index 4d3b72bae64115..92e267f17d08ea 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx @@ -21,6 +21,7 @@ import { capitalize, isFunction } from 'lodash'; import React, { MouseEvent } from 'react'; import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; +import { EuiButton } from '@elastic/eui'; import { TopNavMenuData } from './top_nav_menu_data'; export function TopNavMenuItem(props: TopNavMenuData) { @@ -39,14 +40,20 @@ export function TopNavMenuItem(props: TopNavMenuData) { props.run(e.currentTarget); } - const btn = ( - + const commonButtonProps = { + isDisabled: isDisabled(), + onClick: handleClick, + iconType: props.iconType, + iconSide: props.iconSide, + 'data-test-subj': props.testId, + }; + + const btn = props.emphasize ? ( + + {capitalize(props.label || props.id!)} + + ) : ( + {capitalize(props.label || props.id!)} ); @@ -54,9 +61,8 @@ export function TopNavMenuItem(props: TopNavMenuData) { const tooltip = getTooltip(); if (tooltip) { return {btn}; - } else { - return btn; } + return btn; } TopNavMenuItem.defaultProps = { diff --git a/test/functional/apps/dashboard/create_and_add_embeddables.js b/test/functional/apps/dashboard/create_and_add_embeddables.js index 5ebb9fdf6330ff..3ce8e353e61fc7 100644 --- a/test/functional/apps/dashboard/create_and_add_embeddables.js +++ b/test/functional/apps/dashboard/create_and_add_embeddables.js @@ -41,9 +41,24 @@ export default function({ getService, getPageObjects }) { }); describe('add new visualization link', () => { - it('adds a new visualization', async () => { + it('adds new visualiztion via the top nav link', async () => { const originalPanelCount = await PageObjects.dashboard.getPanelCount(); await PageObjects.dashboard.switchToEditMode(); + await dashboardAddPanel.clickCreateNewLink(); + await PageObjects.visualize.clickAreaChart(); + await PageObjects.visualize.clickNewSearch(); + await PageObjects.visualize.saveVisualizationExpectSuccess( + 'visualization from top nav add new panel' + ); + await retry.try(async () => { + const panelCount = await PageObjects.dashboard.getPanelCount(); + expect(panelCount).to.eql(originalPanelCount + 1); + }); + await PageObjects.dashboard.waitForRenderComplete(); + }); + + it('adds a new visualization', async () => { + const originalPanelCount = await PageObjects.dashboard.getPanelCount(); await dashboardAddPanel.ensureAddPanelIsShowing(); await dashboardAddPanel.clickAddNewEmbeddableLink('visualization'); await PageObjects.visualize.clickAreaChart(); diff --git a/test/functional/services/dashboard/add_panel.js b/test/functional/services/dashboard/add_panel.js index 91e7c15c4f1d9a..62592039821611 100644 --- a/test/functional/services/dashboard/add_panel.js +++ b/test/functional/services/dashboard/add_panel.js @@ -32,6 +32,13 @@ export function DashboardAddPanelProvider({ getService, getPageObjects }) { await PageObjects.common.sleep(500); } + async clickCreateNewLink() { + log.debug('DashboardAddPanel.clickAddNewPanelButton'); + await testSubjects.click('dashboardAddNewPanelButton'); + // Give some time for the animation to complete + await PageObjects.common.sleep(500); + } + async clickAddNewEmbeddableLink(type) { await testSubjects.click('createNew'); await testSubjects.click(`createNew-${type}`);