mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
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> Co-authored-by: Ryan Keairns <rkeairns@chef.io>
This commit is contained in:
parent
51c9b97124
commit
1faabde190
11 changed files with 152 additions and 34 deletions
|
@ -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,
|
||||
|
|
|
@ -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}
|
||||
*/
|
||||
|
|
|
@ -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',
|
||||
};
|
||||
|
|
19
src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap
generated
Normal file
19
src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TopNavMenu Should render emphasized item which should be clickable 1`] = `
|
||||
<EuiButton
|
||||
fill={true}
|
||||
iconSide="right"
|
||||
iconType="beaker"
|
||||
isDisabled={false}
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
style={
|
||||
Object {
|
||||
"fontSize": "smaller",
|
||||
}
|
||||
}
|
||||
>
|
||||
Test
|
||||
</EuiButton>
|
||||
`;
|
|
@ -1,7 +1,11 @@
|
|||
.kbnTopNavMenu__wrapper {
|
||||
z-index: 5;
|
||||
|
||||
.kbnTopNavMenu {
|
||||
padding: $euiSizeS 0px $euiSizeXS;
|
||||
.kbnTopNavMenu {
|
||||
padding: $euiSizeS 0;
|
||||
|
||||
.kbnTopNavItemEmphasized {
|
||||
padding: 0 $euiSizeS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
@ -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}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ButtonIconSide } from '@elastic/eui';
|
||||
|
||||
export type TopNavMenuAction = (anchorElement: EventTarget) => 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 {
|
||||
|
|
|
@ -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',
|
||||
|
@ -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',
|
||||
iconType: 'beaker',
|
||||
iconSide: 'right',
|
||||
emphasize: true,
|
||||
run: jest.fn(),
|
||||
};
|
||||
|
||||
const component = shallowWithIntl(<TopNavMenuItem {...data} />);
|
||||
const event = { currentTarget: { value: 'a' } };
|
||||
component.simulate('click', event);
|
||||
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(),
|
||||
};
|
||||
|
||||
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 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(),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 = (
|
||||
<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>
|
||||
);
|
||||
|
@ -54,9 +61,8 @@ export function TopNavMenuItem(props: TopNavMenuData) {
|
|||
const tooltip = getTooltip();
|
||||
if (tooltip) {
|
||||
return <EuiToolTip content={tooltip}>{btn}</EuiToolTip>;
|
||||
} else {
|
||||
return btn;
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
TopNavMenuItem.defaultProps = {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -30,6 +30,13 @@ export function DashboardAddPanelProvider({ getService, getPageObjects }) {
|
|||
await testSubjects.click('dashboardAddPanelButton');
|
||||
}
|
||||
|
||||
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}`);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue