Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] allow saving maps to dashboards #88759

Merged
merged 7 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@
"ui": true,
"server": true,
"extraPublicDirs": ["common/constants"],
"requiredBundles": ["kibanaReact", "kibanaUtils", "home", "mapsOss"]
"requiredBundles": ["kibanaReact", "kibanaUtils", "home", "mapsOss", "presentationUtil"]
}
15 changes: 13 additions & 2 deletions x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,12 @@ export class SavedMap {
returnToOrigin,
newTags,
saveByReference,
dashboardId,
}: OnSaveProps & {
returnToOrigin: boolean;
returnToOrigin?: boolean;
newTags?: string[];
saveByReference: boolean;
dashboardId?: string | null;
}) {
if (!this._attributes) {
throw new Error('Invalid usage, must await whenReady before calling save');
Expand Down Expand Up @@ -337,14 +339,23 @@ export class SavedMap {
});
return;
}
this._getStateTransfer().navigateToWithEmbeddablePackage(this._originatingApp, {
await this._getStateTransfer().navigateToWithEmbeddablePackage(this._originatingApp, {
state: {
embeddableId: newCopyOnSave ? undefined : this._embeddableId,
type: MAP_SAVED_OBJECT_TYPE,
input: updatedMapEmbeddableInput,
},
});
return;
} else if (dashboardId) {
await this._getStateTransfer().navigateToWithEmbeddablePackage('dashboards', {
state: {
type: MAP_SAVED_OBJECT_TYPE,
input: updatedMapEmbeddableInput,
},
path: dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`,
});
return;
}

this._mapEmbeddableInput = updatedMapEmbeddableInput;
Expand Down
108 changes: 62 additions & 46 deletions x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Adapters } from 'src/plugins/inspector/public';
import {
getCoreChrome,
getMapsCapabilities,
getIsAllowByValueEmbeddables,
getInspector,
getCoreI18n,
getSavedObjectsClient,
Expand All @@ -25,6 +26,7 @@ import {
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
import { SavedMap } from './saved_map';
import { getMapEmbeddableDisplayName } from '../../../common/i18n_getters';
import { SavedObjectSaveModalDashboard } from '../../../../../../src/plugins/presentation_util/public';

export function getTopNavConfig({
savedMap,
Expand Down Expand Up @@ -139,53 +141,67 @@ export function getTopNavConfig({
/>
) : undefined;

const saveModal = (
<SavedObjectSaveModalOrigin
originatingApp={savedMap.getOriginatingApp()}
getAppNameFromId={savedMap.getAppNameFromId}
onSave={async (props: OnSaveProps & { returnToOrigin: boolean }) => {
try {
await checkForDuplicateTitle(
{
id: props.newCopyOnSave ? undefined : savedMap.getSavedObjectId(),
title: props.newTitle,
copyOnSave: props.newCopyOnSave,
lastSavedTitle: savedMap.getSavedObjectId() ? savedMap.getTitle() : '',
getEsType: () => MAP_SAVED_OBJECT_TYPE,
getDisplayName: getMapEmbeddableDisplayName,
},
props.isTitleDuplicateConfirmed,
props.onTitleDuplicate,
{
savedObjectsClient: getSavedObjectsClient(),
overlays: getCoreOverlays(),
}
);
} catch (e) {
// ignore duplicate title failure, user notified in save modal
return {};
}
const saveModalProps = {
onSave: async (
props: OnSaveProps & { returnToOrigin?: boolean; dashboardId?: string | null }
) => {
try {
await checkForDuplicateTitle(
{
id: props.newCopyOnSave ? undefined : savedMap.getSavedObjectId(),
title: props.newTitle,
copyOnSave: props.newCopyOnSave,
lastSavedTitle: savedMap.getSavedObjectId() ? savedMap.getTitle() : '',
getEsType: () => MAP_SAVED_OBJECT_TYPE,
getDisplayName: getMapEmbeddableDisplayName,
},
props.isTitleDuplicateConfirmed,
props.onTitleDuplicate,
{
savedObjectsClient: getSavedObjectsClient(),
overlays: getCoreOverlays(),
}
);
} catch (e) {
// ignore duplicate title failure, user notified in save modal
return {};
}

await savedMap.save({
...props,
newTags: selectedTags,
saveByReference: !props.dashboardId,
});
// showSaveModal wrapper requires onSave to return an object with an id to close the modal after successful save
return { id: 'id' };
},
onClose: () => {},
documentInfo: {
description: mapDescription,
id: savedMap.getSavedObjectId(),
title: savedMap.getTitle(),
},
objectType: i18n.translate('xpack.maps.topNav.saveModalType', {
defaultMessage: 'map',
}),
};

const saveModal =
savedMap.getOriginatingApp() || !getIsAllowByValueEmbeddables() ? (
<SavedObjectSaveModalOrigin
{...saveModalProps}
originatingApp={savedMap.getOriginatingApp()}
getAppNameFromId={savedMap.getAppNameFromId}
options={tagSelector}
/>
) : (
<SavedObjectSaveModalDashboard
{...saveModalProps}
savedObjectsClient={getSavedObjectsClient()}
tagOptions={tagSelector}
/>
);

await savedMap.save({
...props,
newTags: selectedTags,
saveByReference: true,
});
// showSaveModal wrapper requires onSave to return an object with an id to close the modal after successful save
return { id: 'id' };
}}
onClose={() => {}}
documentInfo={{
description: mapDescription,
id: savedMap.getSavedObjectId(),
title: savedMap.getTitle(),
}}
objectType={i18n.translate('xpack.maps.topNav.saveModalType', {
defaultMessage: 'map',
})}
options={tagSelector}
/>
);
showSaveModal(saveModal, getCoreI18n().Context);
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function ({ getPageObjects, getService }) {
after(async () => {
await security.testUser.restoreDefaults();
});

describe('new map', () => {
beforeEach(async () => {
await PageObjects.common.navigateToApp('dashboard');
Expand All @@ -55,7 +56,7 @@ export default function ({ getPageObjects, getService }) {
it('should cut the originator and stay in maps application', async () => {
await PageObjects.maps.saveMap(
'map created from dashboard save and return with originator app cut',
true
false
);
await PageObjects.maps.waitForLayersToLoad();
await testSubjects.missingOrFail('mapSaveAndReturnButton');
Expand Down Expand Up @@ -94,7 +95,7 @@ export default function ({ getPageObjects, getService }) {

describe('save as and uncheck return to origin switch', () => {
it('should cut the originator and stay in maps application', async () => {
await PageObjects.maps.saveMap('Clone 2 of map embeddable example', true);
await PageObjects.maps.saveMap('Clone 2 of map embeddable example', false);
await PageObjects.maps.waitForLayersToLoad();
await testSubjects.missingOrFail('mapSaveAndReturnButton');
await testSubjects.existOrFail('mapSaveButton');
Expand Down
18 changes: 7 additions & 11 deletions x-pack/test/functional/page_objects/gis_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { APP_ID } from '../../../plugins/maps/common/constants';
import { FtrProviderContext } from '../ftr_provider_context';

export function GisPageProvider({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'header', 'timePicker']);
const PageObjects = getPageObjects(['common', 'header', 'timePicker', 'visualize']);

const log = getService('log');
const testSubjects = getService('testSubjects');
Expand Down Expand Up @@ -148,18 +148,14 @@ export function GisPageProvider({ getService, getPageObjects }: FtrProviderConte
await renderable.waitForRender();
}

async saveMap(name: string, uncheckReturnToOriginModeSwitch = false, tags?: string[]) {
async saveMap(name: string, redirectToOrigin = true, tags?: string[]) {
await testSubjects.click('mapSaveButton');
await testSubjects.setValue('savedObjectTitle', name);
if (uncheckReturnToOriginModeSwitch) {
const redirectToOriginCheckboxExists = await testSubjects.exists(
'returnToOriginModeSwitch'
);
if (!redirectToOriginCheckboxExists) {
throw new Error('Unable to uncheck "returnToOriginModeSwitch", it does not exist.');
}
await testSubjects.setEuiSwitch('returnToOriginModeSwitch', 'uncheck');
}
await PageObjects.visualize.setSaveModalValues(name, {
addToDashboard: false,
redirectToOrigin,
saveAsNew: true,
});
if (tags) {
await testSubjects.click('savedObjectTagSelector');
for (const tagName of tags) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const listingTable = getService('listingTable');
const testSubjects = getService('testSubjects');
const find = getService('find');
const PageObjects = getPageObjects(['maps', 'tagManagement', 'common']);
const PageObjects = getPageObjects(['maps', 'tagManagement', 'common', 'visualize']);

/**
* Select tags in the searchbar's tag filter.
Expand Down Expand Up @@ -78,7 +78,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
});

it('allows to select tags for a new map', async () => {
await PageObjects.maps.saveMap('my-new-map', false, ['tag-1', 'tag-3']);
await PageObjects.maps.saveMap('my-new-map', true, ['tag-1', 'tag-3']);

await PageObjects.maps.gotoMapListingPage();
await selectFilterTags('tag-1');
Expand All @@ -91,6 +91,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {

await testSubjects.click('mapSaveButton');
await testSubjects.setValue('savedObjectTitle', 'map-with-new-tag');
await PageObjects.visualize.setSaveModalValues('map-with-new-tag', {
addToDashboard: false,
saveAsNew: true,
});

await testSubjects.click('savedObjectTagSelector');
await testSubjects.click(`tagSelectorOption-action__create`);
Expand Down Expand Up @@ -127,7 +131,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('allows to select tags for an existing map', async () => {
await listingTable.clickItemLink('map', 'map 4 (tag-1)');

await PageObjects.maps.saveMap('map 4 (tag-1)', false, ['tag-3']);
await PageObjects.maps.saveMap('map 4 (tag-1)', true, ['tag-3']);
nreese marked this conversation as resolved.
Show resolved Hide resolved

await PageObjects.maps.gotoMapListingPage();
await selectFilterTags('tag-3');
Expand Down