Skip to content

Commit

Permalink
Dashboard/add panel flow (#59918)
Browse files Browse the repository at this point in the history
Added an emphasize prop to the top nav menu item and used it for a new 'Create new' button which redirects to the 'new visualization' modal.

Co-authored-by: Ryan Keairns <rkeairns@chef.io>
  • Loading branch information
ThomThomson and Ryan Keairns committed Mar 23, 2020
1 parent 3c924d9 commit ec2972c
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -847,7 +847,8 @@ export class DashboardAppController {

showCloneModal(onClone, currentTitle);
};
navActions[TopNavIds.ADD] = () => {

navActions[TopNavIds.ADD_EXISTING] = () => {
if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) {
openAddPanelFlyout({
embeddable: dashboardContainer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
];
Expand Down Expand Up @@ -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}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/

export const TopNavIds = {
ADD: 'add',
SHARE: 'share',
OPTIONS: 'options',
SAVE: 'save',
Expand All @@ -27,4 +26,5 @@ export const TopNavIds = {
CLONE: 'clone',
FULL_SCREEN: 'fullScreenMode',
VISUALIZE: 'visualize',
ADD_EXISTING: 'addExisting',
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions src/plugins/navigation/public/top_nav_menu/_index.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
.kbnTopNavMenu__wrapper {
z-index: 5;

.kbnTopNavMenu {
padding: $euiSizeS 0px $euiSizeXS;
.kbnTopNavMenu {
padding: $euiSizeS 0;

.kbnTopNavItemEmphasized {
padding: 0 $euiSizeS;
}
}
}
7 changes: 6 additions & 1 deletion src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ export function TopNavMenu(props: TopNavMenuProps) {
if (!config) return;
return config.map((menuItem: TopNavMenuData, i: number) => {
return (
<EuiFlexItem grow={false} key={`nav-menu-${i}`}>
<EuiFlexItem
grow={false}
key={`nav-menu-${i}`}
className={menuItem.emphasize ? 'kbnTopNavItemEmphasized' : ''}
>
<TopNavMenuItem {...menuItem} />
</EuiFlexItem>
);
Expand All @@ -66,6 +70,7 @@ export function TopNavMenu(props: TopNavMenuProps) {
<EuiFlexGroup
data-test-subj="top-nav"
justifyContent="flexStart"
alignItems="center"
gutterSize="none"
className="kbnTopNavMenu"
responsive={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* under the License.
*/

import { ButtonIconSide } from '@elastic/eui';

export type TopNavMenuAction = (anchorElement: EventTarget) => void;

export interface TopNavMenuData {
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(<TopNavMenuItem {...data} />);
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',
Expand Down Expand Up @@ -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(<TopNavMenuItem {...data} />);
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(<TopNavMenuItem {...data} />);
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(),
});
});
});
26 changes: 16 additions & 10 deletions src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -39,24 +40,29 @@ export function TopNavMenuItem(props: TopNavMenuData) {
props.run(e.currentTarget);
}

const btn = (
<EuiButtonEmpty
size="xs"
isDisabled={isDisabled()}
onClick={handleClick}
data-test-subj={props.testId}
className={props.className}
>
const commonButtonProps = {
isDisabled: isDisabled(),
onClick: handleClick,
iconType: props.iconType,
iconSide: props.iconSide,
'data-test-subj': props.testId,
};

const btn = props.emphasize ? (
<EuiButton {...commonButtonProps} size="s" fill style={{ fontSize: 'smaller' }}>
{capitalize(props.label || props.id!)}
</EuiButton>
) : (
<EuiButtonEmpty {...commonButtonProps} size="xs">
{capitalize(props.label || props.id!)}
</EuiButtonEmpty>
);

const tooltip = getTooltip();
if (tooltip) {
return <EuiToolTip content={tooltip}>{btn}</EuiToolTip>;
} else {
return btn;
}
return btn;
}

TopNavMenuItem.defaultProps = {
Expand Down
17 changes: 16 additions & 1 deletion test/functional/apps/dashboard/create_and_add_embeddables.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
7 changes: 7 additions & 0 deletions test/functional/services/dashboard/add_panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
Expand Down

0 comments on commit ec2972c

Please sign in to comment.