From 6d689ddabe3c131e638853a05672978456cc8147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20G=C3=B3mez=20Morales?= Date: Wed, 28 Aug 2024 12:55:45 +0000 Subject: [PATCH 1/4] fix(editor): Add confirmation toast when changing user role --- .../src/plugins/i18n/locales/en.json | 3 +++ .../editor-ui/src/views/SettingsUsersView.vue | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index 551f99beae1f0..89d317d64ea74 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -1678,6 +1678,9 @@ "settings.users.usersInvitedError": "Could not invite users", "settings.users.advancedPermissions.warning": "{link} to unlock the ability to create additional admin users", "settings.users.advancedPermissions.warning.link": "Upgrade", + "settings.users.userRoleUpdated": "Changes saved", + "settings.users.userRoleUpdated.message": "{user} has been successfully updated to a {role}", + "settings.users.userRoleUpdatedError": "Unable to updated role", "settings.api": "API", "settings.n8napi": "n8n API", "settings.log-streaming": "Log Streaming", diff --git a/packages/editor-ui/src/views/SettingsUsersView.vue b/packages/editor-ui/src/views/SettingsUsersView.vue index fe45f63c8552f..a0fea3b4b8ded 100644 --- a/packages/editor-ui/src/views/SettingsUsersView.vue +++ b/packages/editor-ui/src/views/SettingsUsersView.vue @@ -211,7 +211,24 @@ function goToUpgradeAdvancedPermissions() { void uiStore.goToUpgrade('settings-users', 'upgrade-advanced-permissions'); } async function onRoleChange(user: IUser, newRoleName: UpdateGlobalRolePayload['newRoleName']) { - await usersStore.updateGlobalRole({ id: user.id, newRoleName }); + try { + await usersStore.updateGlobalRole({ id: user.id, newRoleName }); + + const role = userRoles.value.find(({ value }) => value === newRoleName)?.label || newRoleName; + + showToast({ + type: 'success', + title: i18n.baseText('settings.users.userRoleUpdated'), + message: i18n.baseText('settings.users.userRoleUpdated.message', { + interpolate: { + user: user.fullName ?? '', + role, + }, + }), + }); + } catch (e) { + showError(e, i18n.baseText('settings.users.userReinviteError')); + } } From 40e3f4ccf972601a1228c8707f3b6c284f260220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20G=C3=B3mez=20Morales?= Date: Wed, 28 Aug 2024 14:20:14 +0000 Subject: [PATCH 2/4] test:(editor): Test user role change --- .../src/views/SettingsUsersView.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/editor-ui/src/views/SettingsUsersView.test.ts b/packages/editor-ui/src/views/SettingsUsersView.test.ts index 7a74341e7677a..c429e2fb2fef6 100644 --- a/packages/editor-ui/src/views/SettingsUsersView.test.ts +++ b/packages/editor-ui/src/views/SettingsUsersView.test.ts @@ -156,4 +156,23 @@ describe('SettingsUsersView', () => { id: users[0].id, }); }); + + it("should show success toast when changing a user's role", async () => { + const spy = vi.spyOn(usersStore, 'updateGlobalRole'); + + const { getByTestId, getByRole } = createComponentRenderer(SettingsUsersView)({ pinia }); + + const userListItem = getByTestId(`user-list-item-${users.at(-1)?.email}`); + expect(userListItem).toBeInTheDocument(); + + const actionToggle = within(userListItem).getByTestId('user-role-select'); + + const projectSelectDropdownItems = await getDropdownItems(actionToggle); + await userEvent.click(projectSelectDropdownItems[0]); + + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ newRoleName: 'global:member' })); + const toast = getByRole('alert'); + expect(toast).toBeInTheDocument(); + expect(toast.textContent).toContain('toast'); + }); }); From cab4c02c9fb9c1eeb30bb7cea75f2daeec8cdc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20G=C3=B3mez=20Morales?= Date: Thu, 29 Aug 2024 07:29:16 +0000 Subject: [PATCH 3/4] test(editor): rename variable and fix test --- .../src/views/SettingsUsersView.test.ts | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/editor-ui/src/views/SettingsUsersView.test.ts b/packages/editor-ui/src/views/SettingsUsersView.test.ts index c429e2fb2fef6..7b0e7259b06cc 100644 --- a/packages/editor-ui/src/views/SettingsUsersView.test.ts +++ b/packages/editor-ui/src/views/SettingsUsersView.test.ts @@ -17,6 +17,16 @@ import { useSettingsStore } from '@/stores/settings.store'; import { defaultSettings } from '@/__tests__/defaults'; import { ProjectTypes } from '@/types/projects.types'; +const showToast = vi.fn(); +const showError = vi.fn(); + +vi.mock('@/composables/useToast', () => ({ + useToast: () => ({ + showToast, + showError, + }), +})); + const wrapperComponentWithModal = { components: { SettingsUsersView, ModalRoot, DeleteUserModal }, template: ` @@ -71,6 +81,9 @@ describe('SettingsUsersView', () => { vi.spyOn(projectsStore, 'projects', 'get').mockReturnValue(projects); usersStore.currentUserId = loggedInUser.id; + + showToast.mockReset(); + showError.mockReset(); }); afterEach(() => { @@ -158,21 +171,26 @@ describe('SettingsUsersView', () => { }); it("should show success toast when changing a user's role", async () => { - const spy = vi.spyOn(usersStore, 'updateGlobalRole'); + const updateGlobalRoleSpy = vi.spyOn(usersStore, 'updateGlobalRole').mockResolvedValue(); - const { getByTestId, getByRole } = createComponentRenderer(SettingsUsersView)({ pinia }); + const { getByTestId, getByRole, getAllByRole } = createComponentRenderer(SettingsUsersView)({ + pinia, + }); const userListItem = getByTestId(`user-list-item-${users.at(-1)?.email}`); expect(userListItem).toBeInTheDocument(); - const actionToggle = within(userListItem).getByTestId('user-role-select'); + const roleSelect = within(userListItem).getByTestId('user-role-select'); - const projectSelectDropdownItems = await getDropdownItems(actionToggle); - await userEvent.click(projectSelectDropdownItems[0]); + const roleDropdownItems = await getDropdownItems(roleSelect); + await userEvent.click(roleDropdownItems[0]); + + expect(updateGlobalRoleSpy).toHaveBeenCalledWith( + expect.objectContaining({ newRoleName: 'global:member' }), + ); - expect(spy).toHaveBeenCalledWith(expect.objectContaining({ newRoleName: 'global:member' })); - const toast = getByRole('alert'); - expect(toast).toBeInTheDocument(); - expect(toast.textContent).toContain('toast'); + expect(showToast).toHaveBeenCalledWith( + expect.objectContaining({ type: 'success', message: expect.stringContaining('Member') }), + ); }); }); From d5d8102725b46e9cfc211d018a60a2b847a65019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20G=C3=B3mez=20Morales?= Date: Thu, 29 Aug 2024 07:34:00 +0000 Subject: [PATCH 4/4] test(editor): remove unused variables --- packages/editor-ui/src/views/SettingsUsersView.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/src/views/SettingsUsersView.test.ts b/packages/editor-ui/src/views/SettingsUsersView.test.ts index 7b0e7259b06cc..7a4fe732a6788 100644 --- a/packages/editor-ui/src/views/SettingsUsersView.test.ts +++ b/packages/editor-ui/src/views/SettingsUsersView.test.ts @@ -173,7 +173,7 @@ describe('SettingsUsersView', () => { it("should show success toast when changing a user's role", async () => { const updateGlobalRoleSpy = vi.spyOn(usersStore, 'updateGlobalRole').mockResolvedValue(); - const { getByTestId, getByRole, getAllByRole } = createComponentRenderer(SettingsUsersView)({ + const { getByTestId } = createComponentRenderer(SettingsUsersView)({ pinia, });