Skip to content

Commit

Permalink
[Dashboard] Adds Save as button to top menu (#90320)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
cqliu1 and kibanamachine authored Feb 11, 2021
1 parent befb7c6 commit 30e86ac
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,33 @@ export function DashboardTopNav({
dashboardStateManager,
]);

const runQuickSave = useCallback(async () => {
const currentTitle = dashboardStateManager.getTitle();
const currentDescription = dashboardStateManager.getDescription();
const currentTimeRestore = dashboardStateManager.getTimeRestore();

let currentTags: string[] = [];
if (savedObjectsTagging) {
const dashboard = dashboardStateManager.savedDashboard;
if (savedObjectsTagging.ui.hasTagDecoration(dashboard)) {
currentTags = dashboard.getTags();
}
}

save({}).then((response: SaveResult) => {
// If the save wasn't successful, put the original values back.
if (!(response as { id: string }).id) {
dashboardStateManager.setTitle(currentTitle);
dashboardStateManager.setDescription(currentDescription);
dashboardStateManager.setTimeRestore(currentTimeRestore);
if (savedObjectsTagging) {
dashboardStateManager.setTags(currentTags);
}
}
return response;
});
}, [save, savedObjectsTagging, dashboardStateManager]);

const runClone = useCallback(() => {
const currentTitle = dashboardStateManager.getTitle();
const onClone = async (
Expand Down Expand Up @@ -356,9 +383,8 @@ export function DashboardTopNav({
[TopNavIds.ENTER_EDIT_MODE]: () => onChangeViewMode(ViewMode.EDIT),
[TopNavIds.DISCARD_CHANGES]: onDiscardChanges,
[TopNavIds.SAVE]: runSave,
[TopNavIds.QUICK_SAVE]: runQuickSave,
[TopNavIds.CLONE]: runClone,
[TopNavIds.ADD_EXISTING]: addFromLibrary,
[TopNavIds.VISUALIZE]: createNew,
[TopNavIds.OPTIONS]: (anchorElement) => {
showOptionsPopover({
anchorElement,
Expand Down Expand Up @@ -394,10 +420,9 @@ export function DashboardTopNav({
onDiscardChanges,
onChangeViewMode,
savedDashboard,
addFromLibrary,
createNew,
runClone,
runSave,
runQuickSave,
share,
]);

Expand All @@ -419,11 +444,11 @@ export function DashboardTopNav({
const showFilterBar = shouldShowFilterBar(Boolean(embedSettings?.forceHideFilterBar));
const showSearchBar = showQueryBar || showFilterBar;

const topNav = getTopNavConfig(
viewMode,
dashboardTopNavActions,
dashboardCapabilities.hideWriteControls
);
const topNav = getTopNavConfig(viewMode, dashboardTopNavActions, {
hideWriteControls: dashboardCapabilities.hideWriteControls,
isNewDashboard: !savedDashboard.id,
isDirty: dashboardStateManager.isDirty,
});

return {
appName: 'dashboard',
Expand Down
104 changes: 51 additions & 53 deletions src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import { NavAction } from '../../types';
export function getTopNavConfig(
dashboardMode: ViewMode,
actions: { [key: string]: NavAction },
hideWriteControls: boolean
options: { hideWriteControls: boolean; isNewDashboard: boolean; isDirty: boolean }
) {
switch (dashboardMode) {
case ViewMode.VIEW:
return hideWriteControls
return options.hideWriteControls
? [
getFullScreenConfig(actions[TopNavIds.FULL_SCREEN]),
getShareConfig(actions[TopNavIds.SHARE]),
Expand All @@ -36,20 +36,39 @@ export function getTopNavConfig(
getEditConfig(actions[TopNavIds.ENTER_EDIT_MODE]),
];
case ViewMode.EDIT:
return [
getOptionsConfig(actions[TopNavIds.OPTIONS]),
getShareConfig(actions[TopNavIds.SHARE]),
getAddConfig(actions[TopNavIds.ADD_EXISTING]),
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
getSaveConfig(actions[TopNavIds.SAVE]),
getCreateNewConfig(actions[TopNavIds.VISUALIZE]),
];
return options.isNewDashboard
? [
getOptionsConfig(actions[TopNavIds.OPTIONS]),
getShareConfig(actions[TopNavIds.SHARE]),
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
getSaveConfig(actions[TopNavIds.SAVE], options.isNewDashboard),
]
: [
getOptionsConfig(actions[TopNavIds.OPTIONS]),
getShareConfig(actions[TopNavIds.SHARE]),
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
getSaveConfig(actions[TopNavIds.SAVE]),
getQuickSave(actions[TopNavIds.QUICK_SAVE]),
];
default:
return [];
}
}

function getSaveButtonLabel() {
return i18n.translate('dashboard.topNave.saveButtonAriaLabel', {
defaultMessage: 'save',
});
}

function getSaveAsButtonLabel() {
return i18n.translate('dashboard.topNave.saveAsButtonAriaLabel', {
defaultMessage: 'save as',
});
}

function getFullScreenConfig(action: NavAction) {
return {
id: 'full-screen',
Expand Down Expand Up @@ -89,17 +108,32 @@ function getEditConfig(action: NavAction) {
/**
* @returns {kbnTopNavConfig}
*/
function getSaveConfig(action: NavAction) {
function getQuickSave(action: NavAction) {
return {
id: 'save',
label: i18n.translate('dashboard.topNave.saveButtonAriaLabel', {
defaultMessage: 'save',
}),
id: 'quick-save',
emphasize: true,
label: getSaveButtonLabel(),
description: i18n.translate('dashboard.topNave.saveConfigDescription', {
defaultMessage: 'Save your dashboard',
defaultMessage: 'Quick save your dashboard without any prompts',
}),
testId: 'dashboardQuickSaveMenuItem',
run: action,
};
}

/**
* @returns {kbnTopNavConfig}
*/
function getSaveConfig(action: NavAction, isNewDashboard = false) {
return {
id: 'save',
label: isNewDashboard ? getSaveButtonLabel() : getSaveAsButtonLabel(),
description: i18n.translate('dashboard.topNave.saveAsConfigDescription', {
defaultMessage: 'Save as a new dashboard',
}),
testId: 'dashboardSaveMenuItem',
run: action,
emphasize: isNewDashboard,
};
}

Expand Down Expand Up @@ -157,42 +191,6 @@ function getCloneConfig(action: NavAction) {
/**
* @returns {kbnTopNavConfig}
*/
function getAddConfig(action: NavAction) {
return {
id: 'add',
label: i18n.translate('dashboard.topNave.addButtonAriaLabel', {
defaultMessage: 'Library',
}),
description: i18n.translate('dashboard.topNave.addConfigDescription', {
defaultMessage: 'Add an existing visualization to the dashboard',
}),
testId: 'dashboardAddPanelButton',
run: action,
};
}

/**
* @returns {kbnTopNavConfig}
*/
function getCreateNewConfig(action: NavAction) {
return {
emphasize: true,
iconType: 'plusInCircleFilled',
id: 'addNew',
label: i18n.translate('dashboard.topNave.addNewButtonAriaLabel', {
defaultMessage: 'Create panel',
}),
description: i18n.translate('dashboard.topNave.addNewConfigDescription', {
defaultMessage: 'Create a new panel on this dashboard',
}),
testId: 'dashboardAddNewPanelButton',
run: action,
};
}

// /**
// * @returns {kbnTopNavConfig}
// */
function getShareConfig(action: NavAction | undefined) {
return {
id: 'share',
Expand Down

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

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const PanelToolbar: FC<Props> = ({ onAddPanelClick, onLibraryClick }) =>
size="s"
iconType="plusInCircleFilled"
onClick={onAddPanelClick}
data-test-subj="addVisualizationButton"
data-test-subj="dashboardAddNewPanelButton"
>
{i18n.translate('dashboard.panelToolbar.addPanelButtonLabel', {
defaultMessage: 'Create panel',
Expand All @@ -40,6 +40,7 @@ export const PanelToolbar: FC<Props> = ({ onAddPanelClick, onLibraryClick }) =>
className="panelToolbarButton"
iconType="folderOpen"
onClick={onLibraryClick}
data-test-subj="dashboardAddPanelButton"
>
{i18n.translate('dashboard.panelToolbar.libraryButtonLabel', {
defaultMessage: 'Add from library',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@
export const TopNavIds = {
SHARE: 'share',
OPTIONS: 'options',
QUICK_SAVE: 'quickSave',
SAVE: 'save',
EXIT_EDIT_MODE: 'exitEditMode',
ENTER_EDIT_MODE: 'enterEditMode',
DISCARD_CHANGES: 'discard',
CLONE: 'clone',
FULL_SCREEN: 'fullScreenMode',
VISUALIZE: 'visualize',
ADD_EXISTING: 'addExisting',
};
20 changes: 20 additions & 0 deletions test/functional/apps/dashboard/dashboard_save.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['dashboard', 'header']);
const listingTable = getService('listingTable');
const testSubjects = getService('testSubjects');

// FLAKY: https://github.com/elastic/kibana/issues/89476
describe.skip('dashboard save', function describeIndexTests() {
Expand Down Expand Up @@ -112,5 +113,24 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {

await listingTable.searchAndExpectItemsCount('dashboard', dashboardNameEnterKey, 1);
});

it('Does not show quick save menu item on a new dashboard', async function () {
await PageObjects.dashboard.gotoDashboardLandingPage();
await PageObjects.dashboard.clickNewDashboard();
await PageObjects.dashboard.expectMissingQuickSaveOption();
});

it('Does not show dashboard save modal when on quick save', async function () {
await PageObjects.dashboard.gotoDashboardLandingPage();
await PageObjects.dashboard.clickNewDashboard();
await PageObjects.dashboard.saveDashboard('test quick save');

await PageObjects.dashboard.switchToEditMode();
await PageObjects.dashboard.expectExistsQuickSaveOption();
await PageObjects.dashboard.clickQuickSave();

await testSubjects.existOrFail('saveDashboardSuccess');
await testSubjects.existOrFail('dashboardEditMode');
});
});
}
4 changes: 2 additions & 2 deletions test/functional/apps/dashboard/empty_dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});

it('should add new visualization from dashboard', async () => {
await testSubjects.exists('addVisualizationButton');
await testSubjects.click('addVisualizationButton');
await testSubjects.exists('dashboardAddNewPanelButton');
await testSubjects.click('dashboardAddNewPanelButton');
await dashboardVisualizations.createAndAddMarkdown({
name: 'Dashboard Test Markdown',
markdown: 'Markdown text',
Expand Down
12 changes: 12 additions & 0 deletions test/functional/page_objects/dashboard_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide
await testSubjects.click('dashboardDiscardChanges');
}

public async clickQuickSave() {
log.debug('clickQuickSave');
await testSubjects.click('dashboardQuickSaveMenuItem');
}

public async clickNewDashboard(continueEditing = false) {
await listingTable.clickNewButton('createDashboardPromptButton');
if (await testSubjects.exists('dashboardCreateConfirm')) {
Expand Down Expand Up @@ -583,6 +588,13 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide
await testSubjects.missingOrFail('dashboardSaveMenuItem');
}

public async expectMissingQuickSaveOption() {
await testSubjects.missingOrFail('dashboardQuickSaveMenuItem');
}
public async expectExistsQuickSaveOption() {
await testSubjects.existOrFail('dashboardQuickSaveMenuItem');
}

public async getNotLoadedVisualizations(vizList: string[]) {
const checkList = [];
for (const name of vizList) {
Expand Down
2 changes: 1 addition & 1 deletion test/functional/services/dashboard/visualizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F

async clickAddVisualizationButton() {
log.debug('DashboardVisualizations.clickAddVisualizationButton');
await testSubjects.click('addVisualizationButton');
await testSubjects.click('dashboardAddNewPanelButton');
}

async isNewVisDialogShowing() {
Expand Down
4 changes: 2 additions & 2 deletions test/new_visualize_flow/dashboard_embedding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('adding a metric visualization', async function () {
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
expect(originalPanelCount).to.eql(0);
await testSubjects.exists('addVisualizationButton');
await testSubjects.click('addVisualizationButton');
await testSubjects.exists('dashboardAddNewPanelButton');
await testSubjects.click('dashboardAddNewPanelButton');
await dashboardVisualizations.createAndEmbedMetric('Embedding Vis Test');
await PageObjects.dashboard.waitForRenderComplete();
await dashboardExpect.metricValuesExist(['0']);
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -660,10 +660,6 @@
"dashboard.topNav.saveModal.storeTimeWithDashboardFormRowHelpText": "有効化すると、ダッシュボードが読み込まれるごとに現在選択された時刻の時間フィルターが変更されます。",
"dashboard.topNav.saveModal.storeTimeWithDashboardFormRowLabel": "ダッシュボードに時刻を保存",
"dashboard.topNav.showCloneModal.dashboardCopyTitle": "{title}のコピー",
"dashboard.topNave.addButtonAriaLabel": "ライブラリ",
"dashboard.topNave.addConfigDescription": "既存のビジュアライゼーションをダッシュボードに追加",
"dashboard.topNave.addNewButtonAriaLabel": "パネルの作成",
"dashboard.topNave.addNewConfigDescription": "このダッシュボードに新規パネルを作成",
"dashboard.topNave.cancelButtonAriaLabel": "キャンセル",
"dashboard.topNave.cloneButtonAriaLabel": "クローンを作成",
"dashboard.topNave.cloneConfigDescription": "ダッシュボードのコピーを作成します",
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -660,11 +660,7 @@
"dashboard.topNav.saveModal.storeTimeWithDashboardFormRowHelpText": "每次加载此仪表板时,都会将时间筛选更改为当前选定的时间。",
"dashboard.topNav.saveModal.storeTimeWithDashboardFormRowLabel": "将时间随仪表板保存",
"dashboard.topNav.showCloneModal.dashboardCopyTitle": "{title} 副本",
"dashboard.topNave.addButtonAriaLabel": "库",
"dashboard.topNave.addConfigDescription": "将现有可视化添加到仪表板",
"dashboard.topNave.cancelButtonAriaLabel": "取消",
"dashboard.topNave.addNewButtonAriaLabel": "创建面板",
"dashboard.topNave.addNewConfigDescription": "在此仪表板上创建新的面板",
"dashboard.topNave.cloneButtonAriaLabel": "克隆",
"dashboard.topNave.cloneConfigDescription": "创建仪表板的副本",
"dashboard.topNave.editButtonAriaLabel": "编辑",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export default function ({ getPageObjects, getService }) {

it('adds Lens visualization to empty dashboard', async () => {
const title = 'Dashboard Test Lens';
await testSubjects.exists('addVisualizationButton');
await testSubjects.click('addVisualizationButton');
await testSubjects.exists('dashboardAddNewPanelButton');
await testSubjects.click('dashboardAddNewPanelButton');
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
await PageObjects.lens.createAndAddLensFromDashboard({ title, redirectToOrigin: true });
await PageObjects.dashboard.waitForRenderComplete();
Expand Down

0 comments on commit 30e86ac

Please sign in to comment.