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

Fixes issue with removing spaces from related objects in share to space action #169177

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
42eca44
Fixes issue with removing spaces from related objects in share to spa…
jeramysoucy Oct 17, 2023
0be4242
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Oct 17, 2023
4851a03
Merge branch 'main' into fixes-unsharing-referenced-saved-objects
jeramysoucy Oct 18, 2023
9f93e7e
Adds functional tests for unsharing changes.
jeramysoucy Oct 18, 2023
943a37f
Removes console statement
jeramysoucy Oct 18, 2023
fdf7b55
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Oct 18, 2023
5d96227
Updates toast messages
jeramysoucy Oct 18, 2023
beb7e52
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Oct 18, 2023
c680705
Removes unused toastText property
jeramysoucy Oct 18, 2023
d7f74a9
Updates execution of operations to be parallel. Improves toast messag…
jeramysoucy Oct 19, 2023
40736d8
Merge branch 'main' into fixes-unsharing-referenced-saved-objects
jeramysoucy Oct 19, 2023
630d94e
Updates toast error to account for remove only operation.
jeramysoucy Oct 19, 2023
d426fa9
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Oct 19, 2023
42dacbc
Really fixes toast messages. I mean it this time.
jeramysoucy Oct 19, 2023
9e2f0d8
Merge branch 'main' into fixes-unsharing-referenced-saved-objects
jeramysoucy Oct 19, 2023
323cb67
Removes unused var
jeramysoucy Oct 19, 2023
e9aac2a
Removes console statement
jeramysoucy Oct 19, 2023
7e8b340
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Oct 19, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const SelectableSpacesControl = (props: Props) => {
content={
<FormattedMessage
id="xpack.spaces.management.copyToSpace.selectSpacesControl.disabledTooltip"
defaultMessage="The object already exists in this space."
defaultMessage="The object or a related object already exists in this space."
/>
}
position="left"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const APPEND_PROHIBITED = (
defaultMessage: 'Cannot share to this space',
})}
content={i18n.translate('xpack.spaces.shareToSpace.prohibitedSpaceTooltip', {
defaultMessage: 'A copy of this saved object exists in this space.',
defaultMessage: 'A copy of this saved object or a related object exists in this space.',
})}
position="left"
type="iInCircle"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ const ALL_SPACES_PROHIBITED_TOOLTIP = (
)}
content={i18n.translate(
'xpack.spaces.shareToSpace.shareModeControl.shareToAllSpaces.allSpacesProhibitedTooltipContent',
{ defaultMessage: 'A copy of this saved object exists in at least one other space.' }
{
defaultMessage:
'A copy of this saved object or a related object exists in at least one other space.',
}
)}
position="left"
type="iInCircle"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,110 @@ describe('ShareToSpaceFlyout', () => {
expect(onClose).toHaveBeenCalledTimes(1);
});

describe('handles related objects correctly', () => {
const relatedObject = {
type: 'index-pattern',
id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d',
spaces: ['my-active-space', 'space-1'],
inboundReferences: [
{
type: 'dashboard',
id: 'my-dash',
name: 'foo',
},
],
};

it('adds spaces to related objects when only adding spaces', async () => {
const { wrapper, onClose, mockSpacesManager, mockToastNotifications, savedObjectToShare } =
await setup({
additionalShareableReferences: [relatedObject],
});

expect(wrapper.find(ShareToSpaceForm)).toHaveLength(1);
expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0);
expect(wrapper.find(NoSpacesAvailable)).toHaveLength(0);

changeSpaceSelection(wrapper, ['space-1', 'space-2']);
await clickButton(wrapper, 'save');

const expectedObjects: Array<{ type: string; id: string }> = [
savedObjectToShare,
relatedObject,
].map(({ type, id }) => ({
type,
id,
}));
expect(mockSpacesManager.updateSavedObjectsSpaces).toBeCalledTimes(1);
expect(mockSpacesManager.updateSavedObjectsSpaces).toHaveBeenCalledWith(
expectedObjects,
['space-2'],
[]
);

expect(mockToastNotifications.addSuccess).toHaveBeenCalledTimes(1);
expect(mockToastNotifications.addError).not.toHaveBeenCalled();
expect(onClose).toHaveBeenCalledTimes(1);
});

it('does not remove spaces from related objects when only removing spaces', async () => {
const { wrapper, onClose, mockSpacesManager, mockToastNotifications, savedObjectToShare } =
await setup({
additionalShareableReferences: [relatedObject],
});

expect(wrapper.find(ShareToSpaceForm)).toHaveLength(1);
expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0);
expect(wrapper.find(NoSpacesAvailable)).toHaveLength(0);

changeSpaceSelection(wrapper, []);
await clickButton(wrapper, 'save');

expect(mockSpacesManager.updateSavedObjectsSpaces).toBeCalledTimes(1);
expect(mockSpacesManager.updateSavedObjectsSpaces).toHaveBeenCalledWith(
[{ type: savedObjectToShare.type, id: savedObjectToShare.id }],
[],
['space-1']
);

expect(mockToastNotifications.addSuccess).toHaveBeenCalledTimes(1);
expect(mockToastNotifications.addError).not.toHaveBeenCalled();
expect(onClose).toHaveBeenCalledTimes(1);
});

it('adds spaces but does not remove spaces from related objects when adding and removing spaces', async () => {
const { wrapper, onClose, mockSpacesManager, mockToastNotifications, savedObjectToShare } =
await setup({
additionalShareableReferences: [relatedObject],
});

expect(wrapper.find(ShareToSpaceForm)).toHaveLength(1);
expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0);
expect(wrapper.find(NoSpacesAvailable)).toHaveLength(0);

changeSpaceSelection(wrapper, ['space-2', 'space-3']);
await clickButton(wrapper, 'save');

expect(mockSpacesManager.updateSavedObjectsSpaces).toBeCalledTimes(2);
expect(mockSpacesManager.updateSavedObjectsSpaces).toHaveBeenNthCalledWith(
1,
[{ type: savedObjectToShare.type, id: savedObjectToShare.id }],
['space-2', 'space-3'],
['space-1']
);
expect(mockSpacesManager.updateSavedObjectsSpaces).toHaveBeenNthCalledWith(
2,
[{ type: relatedObject.type, id: relatedObject.id }],
['space-2', 'space-3'],
[]
);

expect(mockToastNotifications.addSuccess).toHaveBeenCalledTimes(1);
expect(mockToastNotifications.addError).not.toHaveBeenCalled();
expect(onClose).toHaveBeenCalledTimes(1);
});
});

describe('correctly renders share mode control', () => {
function getDescriptionAndWarning(wrapper: ReactWrapper) {
const descriptionNode = findTestSubject(wrapper, 'share-mode-control-description');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,27 +85,55 @@ function createDefaultChangeSpacesHandler(
spacesToRemove: string[]
) => {
const { title } = object;
const objectsToUpdate = objects.map(({ type, id }) => ({ type, id })); // only use 'type' and 'id' fields
const objectsToUpdate: Array<{ type: string; id: string }> = objects.map(({ type, id }) => ({
type,
id,
})); // only use 'type' and 'id' fields
const relativesCount = objects.length - 1;
const toastTitle = i18n.translate('xpack.spaces.shareToSpace.shareSuccessTitle', {
values: { objectNoun: object.noun },
defaultMessage: 'Updated {objectNoun}',
description: `Object noun can be plural or singular, examples: "Updated objects", "Updated job"`,
});
await spacesManager.updateSavedObjectsSpaces(objectsToUpdate, spacesToAdd, spacesToRemove);

// If removing spaces and there are referenced objects ("related objects" in UI),
// only remove spaces from the target object.
if (spacesToRemove.length > 0 && objectsToUpdate.length > 1) {
const indexOfTarget = objectsToUpdate.findIndex((element) => element.id === object.id);
if (indexOfTarget >= 0) {
objectsToUpdate.splice(indexOfTarget, 1);
}

const updateTarget = spacesManager.updateSavedObjectsSpaces(
[{ type: object.type, id: object.id }],
spacesToAdd,
spacesToRemove
);

// Only if there are also spaces being added, affect any referenced/related objects
const updateRelated =
spacesToAdd.length > 0
? spacesManager.updateSavedObjectsSpaces(objectsToUpdate, spacesToAdd, [])
: undefined;

await Promise.all([updateTarget, updateRelated]);
} else {
await spacesManager.updateSavedObjectsSpaces(objectsToUpdate, spacesToAdd, spacesToRemove);
}

const isSharedToAllSpaces = spacesToAdd.includes(ALL_SPACES_ID);
let toastText: string;

if (spacesToAdd.length > 0 && spacesToRemove.length > 0 && !isSharedToAllSpaces) {
toastText = i18n.translate('xpack.spaces.shareToSpace.shareSuccessAddRemoveText', {
defaultMessage: `'{object}' {relativesCount, plural, =0 {was} =1 {and {relativesCount} related object were} other {and {relativesCount} related objects were}} added to {spacesTargetAdd} and removed from {spacesTargetRemove}.`,
defaultMessage: `'{object}' {relativesCount, plural, =0 {was} =1 {and {relativesCount} related object were} other {and {relativesCount} related objects were}} added to {spacesTargetAdd}. '{object}' was removed from {spacesTargetRemove}.`,
values: {
object: title,
relativesCount,
spacesTargetAdd: getSpacesTargetString(spacesToAdd),
spacesTargetRemove: getSpacesTargetString(spacesToRemove),
},
description: `Uses output of xpack.spaces.shareToSpace.spacesTarget or xpack.spaces.shareToSpace.allSpacesTarget as 'spacesTarget...' inputs. Example strings: "'Finance dashboard' was added to 1 space and removed from 2 spaces.", "'Finance dashboard' and 2 related objects were added to 3 spaces and removed from all spaces."`,
description: `Uses output of xpack.spaces.shareToSpace.spacesTarget or xpack.spaces.shareToSpace.allSpacesTarget as 'spacesTarget...' inputs. Example strings: "'Finance dashboard' was added to 1 space. 'Finance dashboard' was removed from 2 spaces.", "'Finance dashboard' and 2 related objects were added to 3 spaces. 'Finance dashboard' was removed from all spaces."`,
});
} else if (spacesToAdd.length > 0) {
toastText = i18n.translate('xpack.spaces.shareToSpace.shareSuccessAddText', {
Expand All @@ -119,13 +147,12 @@ function createDefaultChangeSpacesHandler(
});
} else {
toastText = i18n.translate('xpack.spaces.shareToSpace.shareSuccessRemoveText', {
defaultMessage: `'{object}' {relativesCount, plural, =0 {was} =1 {and {relativesCount} related object were} other {and {relativesCount} related objects were}} removed from {spacesTarget}.`,
defaultMessage: `'{object}' was removed from {spacesTarget}.`,
values: {
object: title,
relativesCount,
spacesTarget: getSpacesTargetString(spacesToRemove),
},
description: `Uses output of xpack.spaces.shareToSpace.spacesTarget or xpack.spaces.shareToSpace.allSpacesTarget as 'spacesTarget' input. Example strings: "'Finance dashboard' was removed from 1 space.", "'Finance dashboard' and 2 related objects were removed from all spaces."`,
description: `Uses output of xpack.spaces.shareToSpace.spacesTarget or xpack.spaces.shareToSpace.allSpacesTarget as 'spacesTarget' input. Example string: "'Finance dashboard' was removed from 1 space.", "'Finance dashboard' was removed from all spaces."`,
});
}
toastNotifications.addSuccess({ title: toastTitle, text: toastText });
Expand All @@ -149,6 +176,7 @@ export const ShareToSpaceFlyoutInternal = (props: ShareToSpaceFlyoutProps) => {
}),
[object]
);

const {
flyoutIcon,
flyoutTitle = i18n.translate('xpack.spaces.shareToSpace.flyoutTitle', {
Expand Down Expand Up @@ -322,6 +350,15 @@ export const ShareToSpaceFlyoutInternal = (props: ShareToSpaceFlyoutProps) => {
title: i18n.translate('xpack.spaces.shareToSpace.shareErrorTitle', {
values: { objectNoun: savedObjectTarget.noun },
defaultMessage: 'Error updating {objectNoun}',
description: `Object noun can be plural or singular, examples: "Failed to update objects", "Failed to update job"`,
}),
toastMessage: i18n.translate('xpack.spaces.shareToSpace.shareErrorText', {
defaultMessage: `Unable to update '{object}' {relativesCount, plural, =0 {} =1 {or {relativesCount} related object} other {or one or more of {relativesCount} related objects}}.`,
values: {
object: savedObjectTarget.title,
relativesCount: spacesToAdd.length > 0 ? referenceGraph.length - 1 : 0,
},
description: `Uses output of xpack.spaces.shareToSpace.spacesTarget or xpack.spaces.shareToSpace.allSpacesTarget as 'spacesTarget...' inputs. Example strings: "'Finance dashboard' was added to 1 space. 'Finance dashboard' was removed from 2 spaces.", "'Finance dashboard' and 2 related objects were added to 3 spaces. 'Finance dashboard' was removed from all spaces."`,
}),
});
}
Expand Down
Loading