mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Dashboard] Adds Save as button to top menu (#90320)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
befb7c62a5
commit
30e86ac065
13 changed files with 129 additions and 81 deletions
|
@ -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 (
|
||||
|
@ -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,
|
||||
|
@ -394,10 +420,9 @@ export function DashboardTopNav({
|
|||
onDiscardChanges,
|
||||
onChangeViewMode,
|
||||
savedDashboard,
|
||||
addFromLibrary,
|
||||
createNew,
|
||||
runClone,
|
||||
runSave,
|
||||
runQuickSave,
|
||||
share,
|
||||
]);
|
||||
|
||||
|
@ -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',
|
||||
|
|
|
@ -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]),
|
||||
|
@ -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',
|
||||
|
@ -89,17 +108,32 @@ function getEditConfig(action: NavAction) {
|
|||
/**
|
||||
* @returns {kbnTopNavConfig}
|
||||
*/
|
||||
function getSaveConfig(action: NavAction) {
|
||||
function getQuickSave(action: NavAction) {
|
||||
return {
|
||||
id: 'quick-save',
|
||||
emphasize: true,
|
||||
label: getSaveButtonLabel(),
|
||||
description: i18n.translate('dashboard.topNave.saveConfigDescription', {
|
||||
defaultMessage: 'Quick save your dashboard without any prompts',
|
||||
}),
|
||||
testId: 'dashboardQuickSaveMenuItem',
|
||||
run: action,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {kbnTopNavConfig}
|
||||
*/
|
||||
function getSaveConfig(action: NavAction, isNewDashboard = false) {
|
||||
return {
|
||||
id: 'save',
|
||||
label: i18n.translate('dashboard.topNave.saveButtonAriaLabel', {
|
||||
defaultMessage: 'save',
|
||||
}),
|
||||
description: i18n.translate('dashboard.topNave.saveConfigDescription', {
|
||||
defaultMessage: 'Save your dashboard',
|
||||
label: isNewDashboard ? getSaveButtonLabel() : getSaveAsButtonLabel(),
|
||||
description: i18n.translate('dashboard.topNave.saveAsConfigDescription', {
|
||||
defaultMessage: 'Save as a new dashboard',
|
||||
}),
|
||||
testId: 'dashboardSaveMenuItem',
|
||||
run: action,
|
||||
emphasize: isNewDashboard,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
|
|
|
@ -10,7 +10,7 @@ exports[`Storyshots components/PanelToolbar default 1`] = `
|
|||
>
|
||||
<button
|
||||
className="euiButton euiButton--primary euiButton--small euiButton--fill"
|
||||
data-test-subj="addVisualizationButton"
|
||||
data-test-subj="dashboardAddNewPanelButton"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
|
@ -41,6 +41,7 @@ exports[`Storyshots components/PanelToolbar default 1`] = `
|
|||
>
|
||||
<button
|
||||
className="euiButton euiButton--text euiButton--small panelToolbarButton"
|
||||
data-test-subj="dashboardAddPanelButton"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
|
|
|
@ -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',
|
||||
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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')) {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -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": "ダッシュボードのコピーを作成します",
|
||||
|
|
|
@ -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": "编辑",
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue