Skip to content

Commit a33f0c9

Browse files
Merge branch 'master' into no-ts-refs-build
2 parents 399d2d4 + 90049b0 commit a33f0c9

File tree

19 files changed

+204
-140
lines changed

19 files changed

+204
-140
lines changed

src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,33 @@ export function DashboardTopNav({
321321
dashboardStateManager,
322322
]);
323323

324+
const runQuickSave = useCallback(async () => {
325+
const currentTitle = dashboardStateManager.getTitle();
326+
const currentDescription = dashboardStateManager.getDescription();
327+
const currentTimeRestore = dashboardStateManager.getTimeRestore();
328+
329+
let currentTags: string[] = [];
330+
if (savedObjectsTagging) {
331+
const dashboard = dashboardStateManager.savedDashboard;
332+
if (savedObjectsTagging.ui.hasTagDecoration(dashboard)) {
333+
currentTags = dashboard.getTags();
334+
}
335+
}
336+
337+
save({}).then((response: SaveResult) => {
338+
// If the save wasn't successful, put the original values back.
339+
if (!(response as { id: string }).id) {
340+
dashboardStateManager.setTitle(currentTitle);
341+
dashboardStateManager.setDescription(currentDescription);
342+
dashboardStateManager.setTimeRestore(currentTimeRestore);
343+
if (savedObjectsTagging) {
344+
dashboardStateManager.setTags(currentTags);
345+
}
346+
}
347+
return response;
348+
});
349+
}, [save, savedObjectsTagging, dashboardStateManager]);
350+
324351
const runClone = useCallback(() => {
325352
const currentTitle = dashboardStateManager.getTitle();
326353
const onClone = async (
@@ -356,9 +383,8 @@ export function DashboardTopNav({
356383
[TopNavIds.ENTER_EDIT_MODE]: () => onChangeViewMode(ViewMode.EDIT),
357384
[TopNavIds.DISCARD_CHANGES]: onDiscardChanges,
358385
[TopNavIds.SAVE]: runSave,
386+
[TopNavIds.QUICK_SAVE]: runQuickSave,
359387
[TopNavIds.CLONE]: runClone,
360-
[TopNavIds.ADD_EXISTING]: addFromLibrary,
361-
[TopNavIds.VISUALIZE]: createNew,
362388
[TopNavIds.OPTIONS]: (anchorElement) => {
363389
showOptionsPopover({
364390
anchorElement,
@@ -394,10 +420,9 @@ export function DashboardTopNav({
394420
onDiscardChanges,
395421
onChangeViewMode,
396422
savedDashboard,
397-
addFromLibrary,
398-
createNew,
399423
runClone,
400424
runSave,
425+
runQuickSave,
401426
share,
402427
]);
403428

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

422-
const topNav = getTopNavConfig(
423-
viewMode,
424-
dashboardTopNavActions,
425-
dashboardCapabilities.hideWriteControls
426-
);
447+
const topNav = getTopNavConfig(viewMode, dashboardTopNavActions, {
448+
hideWriteControls: dashboardCapabilities.hideWriteControls,
449+
isNewDashboard: !savedDashboard.id,
450+
isDirty: dashboardStateManager.isDirty,
451+
});
427452

428453
return {
429454
appName: 'dashboard',

src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ import { NavAction } from '../../types';
2020
export function getTopNavConfig(
2121
dashboardMode: ViewMode,
2222
actions: { [key: string]: NavAction },
23-
hideWriteControls: boolean
23+
options: { hideWriteControls: boolean; isNewDashboard: boolean; isDirty: boolean }
2424
) {
2525
switch (dashboardMode) {
2626
case ViewMode.VIEW:
27-
return hideWriteControls
27+
return options.hideWriteControls
2828
? [
2929
getFullScreenConfig(actions[TopNavIds.FULL_SCREEN]),
3030
getShareConfig(actions[TopNavIds.SHARE]),
@@ -36,20 +36,39 @@ export function getTopNavConfig(
3636
getEditConfig(actions[TopNavIds.ENTER_EDIT_MODE]),
3737
];
3838
case ViewMode.EDIT:
39-
return [
40-
getOptionsConfig(actions[TopNavIds.OPTIONS]),
41-
getShareConfig(actions[TopNavIds.SHARE]),
42-
getAddConfig(actions[TopNavIds.ADD_EXISTING]),
43-
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
44-
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
45-
getSaveConfig(actions[TopNavIds.SAVE]),
46-
getCreateNewConfig(actions[TopNavIds.VISUALIZE]),
47-
];
39+
return options.isNewDashboard
40+
? [
41+
getOptionsConfig(actions[TopNavIds.OPTIONS]),
42+
getShareConfig(actions[TopNavIds.SHARE]),
43+
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
44+
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
45+
getSaveConfig(actions[TopNavIds.SAVE], options.isNewDashboard),
46+
]
47+
: [
48+
getOptionsConfig(actions[TopNavIds.OPTIONS]),
49+
getShareConfig(actions[TopNavIds.SHARE]),
50+
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
51+
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
52+
getSaveConfig(actions[TopNavIds.SAVE]),
53+
getQuickSave(actions[TopNavIds.QUICK_SAVE]),
54+
];
4855
default:
4956
return [];
5057
}
5158
}
5259

60+
function getSaveButtonLabel() {
61+
return i18n.translate('dashboard.topNave.saveButtonAriaLabel', {
62+
defaultMessage: 'save',
63+
});
64+
}
65+
66+
function getSaveAsButtonLabel() {
67+
return i18n.translate('dashboard.topNave.saveAsButtonAriaLabel', {
68+
defaultMessage: 'save as',
69+
});
70+
}
71+
5372
function getFullScreenConfig(action: NavAction) {
5473
return {
5574
id: 'full-screen',
@@ -89,17 +108,32 @@ function getEditConfig(action: NavAction) {
89108
/**
90109
* @returns {kbnTopNavConfig}
91110
*/
92-
function getSaveConfig(action: NavAction) {
111+
function getQuickSave(action: NavAction) {
93112
return {
94-
id: 'save',
95-
label: i18n.translate('dashboard.topNave.saveButtonAriaLabel', {
96-
defaultMessage: 'save',
97-
}),
113+
id: 'quick-save',
114+
emphasize: true,
115+
label: getSaveButtonLabel(),
98116
description: i18n.translate('dashboard.topNave.saveConfigDescription', {
99-
defaultMessage: 'Save your dashboard',
117+
defaultMessage: 'Quick save your dashboard without any prompts',
118+
}),
119+
testId: 'dashboardQuickSaveMenuItem',
120+
run: action,
121+
};
122+
}
123+
124+
/**
125+
* @returns {kbnTopNavConfig}
126+
*/
127+
function getSaveConfig(action: NavAction, isNewDashboard = false) {
128+
return {
129+
id: 'save',
130+
label: isNewDashboard ? getSaveButtonLabel() : getSaveAsButtonLabel(),
131+
description: i18n.translate('dashboard.topNave.saveAsConfigDescription', {
132+
defaultMessage: 'Save as a new dashboard',
100133
}),
101134
testId: 'dashboardSaveMenuItem',
102135
run: action,
136+
emphasize: isNewDashboard,
103137
};
104138
}
105139

@@ -157,42 +191,6 @@ function getCloneConfig(action: NavAction) {
157191
/**
158192
* @returns {kbnTopNavConfig}
159193
*/
160-
function getAddConfig(action: NavAction) {
161-
return {
162-
id: 'add',
163-
label: i18n.translate('dashboard.topNave.addButtonAriaLabel', {
164-
defaultMessage: 'Library',
165-
}),
166-
description: i18n.translate('dashboard.topNave.addConfigDescription', {
167-
defaultMessage: 'Add an existing visualization to the dashboard',
168-
}),
169-
testId: 'dashboardAddPanelButton',
170-
run: action,
171-
};
172-
}
173-
174-
/**
175-
* @returns {kbnTopNavConfig}
176-
*/
177-
function getCreateNewConfig(action: NavAction) {
178-
return {
179-
emphasize: true,
180-
iconType: 'plusInCircleFilled',
181-
id: 'addNew',
182-
label: i18n.translate('dashboard.topNave.addNewButtonAriaLabel', {
183-
defaultMessage: 'Create panel',
184-
}),
185-
description: i18n.translate('dashboard.topNave.addNewConfigDescription', {
186-
defaultMessage: 'Create a new panel on this dashboard',
187-
}),
188-
testId: 'dashboardAddNewPanelButton',
189-
run: action,
190-
};
191-
}
192-
193-
// /**
194-
// * @returns {kbnTopNavConfig}
195-
// */
196194
function getShareConfig(action: NavAction | undefined) {
197195
return {
198196
id: 'share',

src/plugins/dashboard/public/application/top_nav/panel_toolbar/__snapshots__/panel_toolbar.stories.storyshot

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/plugins/dashboard/public/application/top_nav/panel_toolbar/panel_toolbar.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const PanelToolbar: FC<Props> = ({ onAddPanelClick, onLibraryClick }) =>
2626
size="s"
2727
iconType="plusInCircleFilled"
2828
onClick={onAddPanelClick}
29-
data-test-subj="addVisualizationButton"
29+
data-test-subj="dashboardAddNewPanelButton"
3030
>
3131
{i18n.translate('dashboard.panelToolbar.addPanelButtonLabel', {
3232
defaultMessage: 'Create panel',
@@ -40,6 +40,7 @@ export const PanelToolbar: FC<Props> = ({ onAddPanelClick, onLibraryClick }) =>
4040
className="panelToolbarButton"
4141
iconType="folderOpen"
4242
onClick={onLibraryClick}
43+
data-test-subj="dashboardAddPanelButton"
4344
>
4445
{i18n.translate('dashboard.panelToolbar.libraryButtonLabel', {
4546
defaultMessage: 'Add from library',

src/plugins/dashboard/public/application/top_nav/top_nav_ids.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
export const TopNavIds = {
1010
SHARE: 'share',
1111
OPTIONS: 'options',
12+
QUICK_SAVE: 'quickSave',
1213
SAVE: 'save',
1314
EXIT_EDIT_MODE: 'exitEditMode',
1415
ENTER_EDIT_MODE: 'enterEditMode',
1516
DISCARD_CHANGES: 'discard',
1617
CLONE: 'clone',
1718
FULL_SCREEN: 'fullScreenMode',
18-
VISUALIZE: 'visualize',
19-
ADD_EXISTING: 'addExisting',
2019
};

test/functional/apps/dashboard/dashboard_save.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
1111
export default function ({ getService, getPageObjects }: FtrProviderContext) {
1212
const PageObjects = getPageObjects(['dashboard', 'header']);
1313
const listingTable = getService('listingTable');
14+
const testSubjects = getService('testSubjects');
1415

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

113114
await listingTable.searchAndExpectItemsCount('dashboard', dashboardNameEnterKey, 1);
114115
});
116+
117+
it('Does not show quick save menu item on a new dashboard', async function () {
118+
await PageObjects.dashboard.gotoDashboardLandingPage();
119+
await PageObjects.dashboard.clickNewDashboard();
120+
await PageObjects.dashboard.expectMissingQuickSaveOption();
121+
});
122+
123+
it('Does not show dashboard save modal when on quick save', async function () {
124+
await PageObjects.dashboard.gotoDashboardLandingPage();
125+
await PageObjects.dashboard.clickNewDashboard();
126+
await PageObjects.dashboard.saveDashboard('test quick save');
127+
128+
await PageObjects.dashboard.switchToEditMode();
129+
await PageObjects.dashboard.expectExistsQuickSaveOption();
130+
await PageObjects.dashboard.clickQuickSave();
131+
132+
await testSubjects.existOrFail('saveDashboardSuccess');
133+
await testSubjects.existOrFail('dashboardEditMode');
134+
});
115135
});
116136
}

test/functional/apps/dashboard/edit_visualizations.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,72 @@ export default function ({ getService, getPageObjects }) {
108108
await PageObjects.common.clickConfirmOnModal();
109109
expect(await testSubjects.exists('visualizationLandingPage')).to.be(true);
110110
});
111+
112+
describe('by value', () => {
113+
it('save and return button returns to dashboard after editing visualization with changes saved', async () => {
114+
await PageObjects.common.navigateToApp('dashboard');
115+
await PageObjects.dashboard.clickNewDashboard();
116+
117+
await createMarkdownVis();
118+
119+
const originalPanelCount = PageObjects.dashboard.getPanelCount();
120+
121+
await editMarkdownVis();
122+
await PageObjects.visualize.saveVisualizationAndReturn();
123+
124+
const markdownText = await testSubjects.find('markdownBody');
125+
expect(await markdownText.getVisibleText()).to.eql(modifiedMarkdownText);
126+
127+
const newPanelCount = PageObjects.dashboard.getPanelCount();
128+
expect(newPanelCount).to.eql(originalPanelCount);
129+
});
130+
131+
it('cancel button returns to dashboard after editing visualization without saving', async () => {
132+
await PageObjects.dashboard.gotoDashboardLandingPage();
133+
await PageObjects.dashboard.clickNewDashboard();
134+
135+
await createMarkdownVis();
136+
137+
await editMarkdownVis();
138+
await PageObjects.visualize.cancelAndReturn(true);
139+
140+
const markdownText = await testSubjects.find('markdownBody');
141+
expect(await markdownText.getVisibleText()).to.eql(originalMarkdownText);
142+
});
143+
144+
it('save to library button returns to dashboard after editing visualization with changes saved', async () => {
145+
await PageObjects.dashboard.gotoDashboardLandingPage();
146+
await PageObjects.dashboard.clickNewDashboard();
147+
148+
await createMarkdownVis();
149+
150+
const originalPanelCount = PageObjects.dashboard.getPanelCount();
151+
152+
await editMarkdownVis();
153+
await PageObjects.visualize.saveVisualization('test save to library', {
154+
redirectToOrigin: true,
155+
});
156+
157+
const markdownText = await testSubjects.find('markdownBody');
158+
expect(await markdownText.getVisibleText()).to.eql(modifiedMarkdownText);
159+
160+
const newPanelCount = PageObjects.dashboard.getPanelCount();
161+
expect(newPanelCount).to.eql(originalPanelCount);
162+
});
163+
164+
it('should lose its connection to the dashboard when creating new visualization', async () => {
165+
await PageObjects.visualize.gotoVisualizationLandingPage();
166+
await PageObjects.visualize.clickNewVisualization();
167+
await PageObjects.visualize.clickMarkdownWidget();
168+
await PageObjects.visualize.notLinkedToOriginatingApp();
169+
170+
// return to origin should not be present in save modal
171+
await testSubjects.click('visualizeSaveButton');
172+
const redirectToOriginCheckboxExists = await testSubjects.exists(
173+
'returnToOriginModeSwitch'
174+
);
175+
expect(redirectToOriginCheckboxExists).to.be(false);
176+
});
177+
});
111178
});
112179
}

test/functional/apps/dashboard/empty_dashboard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
4848
});
4949

5050
it('should add new visualization from dashboard', async () => {
51-
await testSubjects.exists('addVisualizationButton');
52-
await testSubjects.click('addVisualizationButton');
51+
await testSubjects.exists('dashboardAddNewPanelButton');
52+
await testSubjects.click('dashboardAddNewPanelButton');
5353
await dashboardVisualizations.createAndAddMarkdown({
5454
name: 'Dashboard Test Markdown',
5555
markdown: 'Markdown text',

0 commit comments

Comments
 (0)