From 5805826994ac982ef9705de75d08488efaabcd1b Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Mon, 3 Jun 2024 17:17:46 +0530 Subject: [PATCH] refactor(sh-admin): improved error handling and dynamic user actions in admin dashboard (#4044) * feat: new helper functions for better error management * refactor: new i18n strings * refactor: better error handling in invite modal and members component * refactor: better user management * refactor: better error handling in config handler * refactor: updated logic of dynamic action row * refactor: better naming for computed properties * feat: new error message when an admin tries to invite himself * refactor: updated error message when user is already invited * refactor: reverted i18n string for user already invited back to the old string * refactor: removed show prop from invite modal * refactor: improved implementation for getting the compiled error messages * feat: new error message when email inputted is of an invalid format * refactor: minor optimization --------- Co-authored-by: jamesgeorge007 --- packages/hoppscotch-sh-admin/locales/en.json | 4 +- .../hoppscotch-sh-admin/src/components.d.ts | 83 ++++++++++--------- .../src/components/teams/Members.vue | 9 +- .../src/components/users/InviteModal.vue | 10 --- .../src/composables/useConfigHandler.ts | 8 +- .../hoppscotch-sh-admin/src/helpers/errors.ts | 56 ++++++++++++- .../src/helpers/userManagement.ts | 18 ++-- .../src/pages/users/index.vue | 39 ++++++--- 8 files changed, 154 insertions(+), 73 deletions(-) diff --git a/packages/hoppscotch-sh-admin/locales/en.json b/packages/hoppscotch-sh-admin/locales/en.json index 68ce20b6..95189969 100644 --- a/packages/hoppscotch-sh-admin/locales/en.json +++ b/packages/hoppscotch-sh-admin/locales/en.json @@ -14,6 +14,7 @@ "client_id": "CLIENT ID", "client_secret": "CLIENT SECRET", "description": "Configure authentication providers for your server", + "provider_not_specified": "Please enable at least one authentication provider", "scope": "SCOPE", "tenant": "TENANT", "title": "Authentication Providers", @@ -146,6 +147,7 @@ "email_failure": "Failed to send invitation", "email_signin_failure": "Failed to login with Email", "email_success": "Email invitation sent successfully", + "emails_cannot_be_same": "You cannot invite yourself, please choose a different email address!!", "enter_team_email": "Please enter email of workspace owner!!", "error": "Something went wrong", "error_auth_providers": "Unable to load auth providers", @@ -171,6 +173,7 @@ "remove_admin_from_users_success": "Admin status removed from selected users!!", "remove_admin_to_delete_user": "Remove admin privilege to delete the user!!", "remove_owner_to_delete_user": "Remove team ownership status to delete the user!!", + "remove_owner_failure_only_one_owner": "Failed to remove member. There should be atleast one owner in a team!!", "remove_admin_for_deletion": "Remove admin status before attempting deletion!!", "remove_owner_for_deletion": "One or more users are team owners. Update ownership before deletion!!", "remove_invitee_failure": "Removal of invitee failed!!", @@ -193,7 +196,6 @@ "sign_in_options": "All sign in option", "sign_out": "Sign out", "team_name_too_short": "Workspace name should be atleast 6 characters long!!", - "team_name_long": "Workspace name should be atleast 6 characters long!!", "user_already_invited": "Failed to send invite. User is already invited!!", "user_not_found": "User not found in the infra!!", "users_to_admin_success": "Selected users are elevated to admin status!!", diff --git a/packages/hoppscotch-sh-admin/src/components.d.ts b/packages/hoppscotch-sh-admin/src/components.d.ts index d26357c8..271876ac 100644 --- a/packages/hoppscotch-sh-admin/src/components.d.ts +++ b/packages/hoppscotch-sh-admin/src/components.d.ts @@ -1,50 +1,51 @@ // generated by unplugin-vue-components // We suggest you to commit this file into source control // Read more: https://github.com/vuejs/core/pull/3399 -import '@vue/runtime-core' +import '@vue/runtime-core'; -export {} +export {}; declare module '@vue/runtime-core' { export interface GlobalComponents { - AppHeader: typeof import('./components/app/Header.vue')['default'] - AppLogin: typeof import('./components/app/Login.vue')['default'] - AppLogout: typeof import('./components/app/Logout.vue')['default'] - AppModal: typeof import('./components/app/Modal.vue')['default'] - AppSidebar: typeof import('./components/app/Sidebar.vue')['default'] - AppToast: typeof import('./components/app/Toast.vue')['default'] - DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default'] - HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'] - HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'] - HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'] - HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'] - HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput'] - HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'] - HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink'] - HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'] - HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture'] - HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'] - HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab'] - HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs'] - HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle'] - IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] - SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default'] - SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default'] - SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default'] - SettingsReset: typeof import('./components/settings/Reset.vue')['default'] - SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default'] - SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default'] - SetupDataSharingAndNewsletter: typeof import('./components/setup/DataSharingAndNewsletter.vue')['default'] - TeamsAdd: typeof import('./components/teams/Add.vue')['default'] - TeamsDetails: typeof import('./components/teams/Details.vue')['default'] - TeamsInvite: typeof import('./components/teams/Invite.vue')['default'] - TeamsMembers: typeof import('./components/teams/Members.vue')['default'] - TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default'] - Tippy: typeof import('vue-tippy')['Tippy'] - UiAutoResetIcon: typeof import('./components/ui/AutoResetIcon.vue')['default'] - UsersDetails: typeof import('./components/users/Details.vue')['default'] - UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default'] - UsersSharedRequests: typeof import('./components/users/SharedRequests.vue')['default'] + AppHeader: typeof import('./components/app/Header.vue')['default']; + AppLogin: typeof import('./components/app/Login.vue')['default']; + AppLogout: typeof import('./components/app/Logout.vue')['default']; + AppModal: typeof import('./components/app/Modal.vue')['default']; + AppSidebar: typeof import('./components/app/Sidebar.vue')['default']; + AppToast: typeof import('./components/app/Toast.vue')['default']; + DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default']; + HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']; + HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']; + HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']; + HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']; + HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']; + HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']; + HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']; + HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']; + HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']; + HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']; + HoppSmartSelectWrapper: typeof import('@hoppscotch/ui')['HoppSmartSelectWrapper']; + HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']; + HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab']; + HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']; + HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']; + IconLucideInbox: typeof import('~icons/lucide/inbox')['default']; + SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default']; + SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default']; + SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default']; + SettingsReset: typeof import('./components/settings/Reset.vue')['default']; + SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default']; + SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default']; + SetupDataSharingAndNewsletter: typeof import('./components/setup/DataSharingAndNewsletter.vue')['default']; + TeamsAdd: typeof import('./components/teams/Add.vue')['default']; + TeamsDetails: typeof import('./components/teams/Details.vue')['default']; + TeamsInvite: typeof import('./components/teams/Invite.vue')['default']; + TeamsMembers: typeof import('./components/teams/Members.vue')['default']; + TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default']; + Tippy: typeof import('vue-tippy')['Tippy']; + UiAutoResetIcon: typeof import('./components/ui/AutoResetIcon.vue')['default']; + UsersDetails: typeof import('./components/users/Details.vue')['default']; + UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default']; + UsersSharedRequests: typeof import('./components/users/SharedRequests.vue')['default']; } - } diff --git a/packages/hoppscotch-sh-admin/src/components/teams/Members.vue b/packages/hoppscotch-sh-admin/src/components/teams/Members.vue index a9d93395..d2d7e9af 100644 --- a/packages/hoppscotch-sh-admin/src/components/teams/Members.vue +++ b/packages/hoppscotch-sh-admin/src/components/teams/Members.vue @@ -168,6 +168,7 @@ import { useRoute } from 'vue-router'; import { useI18n } from '~/composables/i18n'; import { useToast } from '~/composables/toast'; import { useClientHandler } from '~/composables/useClientHandler'; +import { getCompiledErrorMessage } from '~/helpers/errors'; import IconChevronDown from '~icons/lucide/chevron-down'; import IconCircle from '~icons/lucide/circle'; import IconCircleDot from '~icons/lucide/circle-dot'; @@ -353,7 +354,13 @@ const removeExistingTeamMember = async (userID: string, index: number) => { team.value.id )(); if (removeTeamMemberResult.error) { - toast.error(t('state.remove_member_failure')); + const compiledErrorMessage = getCompiledErrorMessage( + removeTeamMemberResult.error.message + ); + + compiledErrorMessage + ? toast.error(compiledErrorMessage) + : toast.error(t('state.remove_member_failure')); } else { team.value.teamMembers = team.value.teamMembers?.filter( (member: any) => member.user.uid !== userID diff --git a/packages/hoppscotch-sh-admin/src/components/users/InviteModal.vue b/packages/hoppscotch-sh-admin/src/components/users/InviteModal.vue index 36c536d4..dee511f1 100644 --- a/packages/hoppscotch-sh-admin/src/components/users/InviteModal.vue +++ b/packages/hoppscotch-sh-admin/src/components/users/InviteModal.vue @@ -1,6 +1,5 @@