From 8809c3b77920eb1352b43197ad282a4f08ff6b12 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:13:53 +0530 Subject: [PATCH 01/60] feat: new mutations for bulk delete, and enabling and disabling of the admin status --- .../helpers/backend/gql/mutations/MakeUsersAdmin.graphql | 3 +++ .../backend/gql/mutations/RemoveUsersAsAdmin.graphql | 3 +++ .../backend/gql/mutations/RemoveUsersByAdmin.graphql | 7 +++++++ 3 files changed, 13 insertions(+) create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUsersAdmin.graphql create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUsersAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUsersAdmin.graphql new file mode 100644 index 0000000000..f936562da1 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUsersAdmin.graphql @@ -0,0 +1,3 @@ +mutation MakeUsersAdmin($userUIDs: [ID!]!) { + makeUsersAdmin(userUIDs: $userUIDs) +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql new file mode 100644 index 0000000000..a37bafdf80 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql @@ -0,0 +1,3 @@ +mutation RemoveUsersAsAdmin($userUIDs: [ID!]!) { + removeUsersAsAdmin(userUIDs: $userUIDs) +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql new file mode 100644 index 0000000000..7933f1a5e8 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql @@ -0,0 +1,7 @@ +mutation RemoveUsersByAdmin($userUIDs: [ID!]!) { + removeUsersByAdmin(userUIDs: $userUIDs) { + userUID + success + errorMessage + } +} From 23ceb116b9ece1b0e1f9f93bf49ead80e55fa064 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:16:39 +0530 Subject: [PATCH 02/60] refactor: implemented bulk actions in users page --- .../src/pages/users/index.vue | 341 ++++++++++++------ 1 file changed, 238 insertions(+), 103 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 30c6c26721..abad9f9d43 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -27,113 +27,140 @@
{{ t('users.load_list_error') }}
- + - - +
{{ t('users.no_users') }}
+
+
+ + + +
+
+
+ + +
@@ -187,9 +232,14 @@ import IconAddUser from '~icons/lucide/user-plus'; import { InviteNewUserDocument, MakeUserAdminDocument, + MakeUsersAdminDocument, RemoveUserAsAdminDocument, + RemoveUsersAsAdminDocument, RemoveUserByAdminDocument, + RemoveUsersByAdminDocument, UsersListDocument, + UsersListQuery, + UserInfoQuery, } from '~/helpers/backend/graphql'; // Get Proper Date Formats @@ -199,6 +249,14 @@ const toast = useToast(); const getCreatedDate = (date: string) => format(new Date(date), 'dd-MM-yyyy'); const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a'); +// Table Headings +const headings = [ + { key: 'uid', label: t('users.id') }, + { key: 'displayName', label: t('users.name') }, + { key: 'email', label: t('users.email') }, + { key: 'createdOn', label: t('users.date') }, +]; + // Get Paginated Results of all the users in the infra const usersPerPage = 20; const { @@ -236,13 +294,19 @@ const sendInvite = async (email: string) => { // Go to Individual User Details Page const router = useRouter(); -const goToUserDetails = (uid: string) => router.push('/users/' + uid); +const goToUserDetails = (user: UserInfoQuery['infra']['userInfo']) => + router.push('/users/' + user.uid); // User Deletion const userDeletion = useMutation(RemoveUserByAdminDocument); const confirmDeletion = ref(false); const deleteUserUID = ref(null); +const deleteUser = (id: string) => { + confirmDeletion.value = true; + deleteUserUID.value = id; +}; + const deleteUserMutation = async (id: string | null) => { if (!id) { confirmDeletion.value = false; @@ -302,11 +366,6 @@ const makeAdminToUser = (id: string) => { adminToUserUID.value = id; }; -const deleteUser = (id: string) => { - confirmDeletion.value = true; - deleteUserUID.value = id; -}; - const makeAdminToUserMutation = async (id: string | null) => { if (!id) { confirmAdminToUser.value = false; @@ -327,4 +386,80 @@ const makeAdminToUserMutation = async (id: string | null) => { confirmAdminToUser.value = false; adminToUserUID.value = null; }; + +const selectedRows = ref([]); + +const usersToAdmin = useMutation(MakeUsersAdminDocument); +const confirmUsersToAdmin = ref(false); + +const makeUsersToAdmin = async () => { + const userUIDs = selectedRows.value.map((user) => user.uid); + console.log(userUIDs); + + const variables = { userUIDs }; + const result = await usersToAdmin.executeMutation(variables); + if (result.error) { + toast.error(t('state.admin_failure')); + } else { + toast.success(t('state.admin_success')); + usersList.value = usersList.value.map((user) => ({ + ...user, + isAdmin: userUIDs.includes(user.uid) ? true : user.isAdmin, + })); + selectedRows.value = []; + } + confirmUsersToAdmin.value = false; +}; + +const adminsToUser = useMutation(RemoveUsersAsAdminDocument); +const confirmAdminsToUsers = ref(false); + +const makeAdminsToUsers = async () => { + const userUIDs = selectedRows.value.map((user) => user.uid); + console.log(userUIDs); + + const variables = { userUIDs }; + const result = await adminsToUser.executeMutation(variables); + if (result.error) { + toast.error(t('state.remove_admin_failure')); + } else { + toast.success(t('state.remove_admin_success')); + usersList.value = usersList.value.map((user) => ({ + ...user, + isAdmin: userUIDs.includes(user.uid) ? false : user.isAdmin, + })); + selectedRows.value = []; + } + confirmAdminsToUsers.value = false; +}; + +const usersDeletion = useMutation(RemoveUsersByAdminDocument); +const confirmUsersDeletion = ref(false); + +const deleteUsers = async () => { + const userUIDs = selectedRows.value.map((user) => user.uid); + console.log(userUIDs); + + const variables = { userUIDs }; + const result = await usersDeletion.executeMutation(variables); + if (result.error) { + toast.error(t('state.delete_user_failure')); + } else { + toast.success(t('state.delete_user_success')); + usersList.value = usersList.value.filter( + (user) => !userUIDs.includes(user.uid) + ); + selectedRows.value = []; + } + confirmUsersDeletion.value = false; +}; + +const handleToggle = (selected: UsersListQuery['infra']['allUsers']) => { + selectedRows.value = selected; + console.log(selectedRows.value); +}; + +const handleInput = (input) => { + console.log(input); +}; From 0083cb767264d1e70fcf64999313b2629e6c52e8 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Mon, 5 Feb 2024 13:06:15 +0530 Subject: [PATCH 03/60] refactor: updated index component to support selected rows as a useVmodel --- .../src/pages/users/index.vue | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index abad9f9d43..c496c96e31 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -32,10 +32,9 @@ :headings="headings" :list="usersList" :checkbox="true" - :selectedRows="selectedRows" + :selected-rows="selectedRows" :search-bar="{ debounce: 300 }" @onRowClicked="goToUserDetails" - @onRowToggled="handleToggle" @search="handleInput" > -
+
+
@@ -236,7 +240,7 @@ import { RemoveUsersAsAdminDocument, RemoveUserByAdminDocument, RemoveUsersByAdminDocument, - UsersListDocument, + UsersListV2Document, UsersListQuery, UserInfoQuery, } from '~/helpers/backend/graphql'; @@ -256,22 +260,31 @@ const headings = [ { key: 'createdOn', label: t('users.date') }, ]; +const searchQuery = ref(''); + // Get Paginated Results of all the users in the infra const usersPerPage = 20; const { fetching, error, goToNextPage: fetchNextUsers, + refetch, list: usersList, hasNextPage, } = usePagedQuery( - UsersListDocument, - (x) => x.infra.allUsers, - (x) => x.uid, + UsersListV2Document, + (x) => x.infra.allUsersV2, usersPerPage, - { cursor: undefined, take: usersPerPage } + { searchString: searchQuery.value, take: usersPerPage, skip: 0 } ); +const handleInput = async (input: string) => { + searchQuery.value = input; + await refetch(searchQuery.value); +}; + +const selectedRows = ref([]); + // Send Invitation through Email const sendInvitation = useMutation(InviteNewUserDocument); const showInviteUserModal = ref(false); @@ -386,8 +399,6 @@ const makeAdminToUserMutation = async (id: string | null) => { adminToUserUID.value = null; }; -const selectedRows = ref([]); - const usersToAdmin = useMutation(MakeUsersAdminDocument); const confirmUsersToAdmin = ref(false); @@ -455,8 +466,4 @@ const deleteUsers = async () => { } confirmUsersDeletion.value = false; }; - -const handleInput = (input) => { - console.log(input); -}; From 9702b2e5aec6a5b3f7ed9fbafc24c87e7e1ce91a Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 6 Feb 2024 11:42:56 +0530 Subject: [PATCH 06/60] feat: new pagination system implemented in users table --- .../src/pages/users/index.vue | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index d85e86ac84..1d3dbff21b 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -5,7 +5,7 @@

{{ t('users.users') }}

-
+
- -
- -
- {{ t('users.show_more') }} - -
@@ -222,8 +214,9 @@ From 7021feb55299e981697d6e047693553c68b1ffb2 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:51:39 +0530 Subject: [PATCH 08/60] style: ui fixes in users page --- .../hoppscotch-sh-admin/src/components.d.ts | 91 ++++++++++--------- .../src/pages/teams/index.vue | 8 +- .../src/pages/users/index.vue | 21 +++-- 3 files changed, 66 insertions(+), 54 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/components.d.ts b/packages/hoppscotch-sh-admin/src/components.d.ts index 671efba5f9..e1ab284047 100644 --- a/packages/hoppscotch-sh-admin/src/components.d.ts +++ b/packages/hoppscotch-sh-admin/src/components.d.ts @@ -1,53 +1,56 @@ // 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'] - HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete'] - 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'] - HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable'] - HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs'] - HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle'] - IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'] - 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']; + HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']; + 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']; + HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable']; + HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']; + HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']; + IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']; + IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']; + IconLucideInbox: typeof import('~icons/lucide/inbox')['default']; + IconLucideSearch: typeof import('~icons/lucide/search')['default']; + IconLucideUser: typeof import('~icons/lucide/user')['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']; + UsersTable: typeof import('./components/users/Table.vue')['default']; } - } diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/index.vue b/packages/hoppscotch-sh-admin/src/pages/teams/index.vue index 6543d6c134..12b988ef35 100644 --- a/packages/hoppscotch-sh-admin/src/pages/teams/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/teams/index.vue @@ -149,9 +149,9 @@ const usersPerPage = computed(() => data.value?.infra.usersCount || 10000); const { list: usersList } = usePagedQuery( UsersListDocument, (x) => x.infra.allUsers, - (x) => x.uid, usersPerPage.value, - { cursor: undefined, take: usersPerPage.value } + { cursor: undefined, take: usersPerPage.value }, + (x) => x.uid ); const allUsersEmail = computed(() => usersList.value.map((user) => user.email)); @@ -168,9 +168,9 @@ const { } = usePagedQuery( TeamListDocument, (x) => x.infra.allTeams, - (x) => x.id, teamsPerPage, - { cursor: undefined, take: teamsPerPage } + { cursor: undefined, take: teamsPerPage }, + (x) => x.id ); // Create Team diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 1d3dbff21b..e53ad19b67 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -15,20 +15,20 @@
-
+
{{ t('users.load_list_error') }}
+ +
([]); // Search + const searchQuery = ref(''); const handleInput = async (input: string) => { searchQuery.value = input; From 94d77a18ca724895de7bbe8e0374088852d449e6 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:06:25 +0530 Subject: [PATCH 09/60] chore: updated debounce value for users table --- .../src/pages/users/index.vue | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index e53ad19b67..f468c0e059 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -21,20 +21,20 @@
-
+ -
{{ t('users.load_list_error') }}
+ - - +
{{ t('users.load_list_error') }}
@@ -182,37 +178,37 @@ /> @@ -220,32 +216,35 @@ diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/UpdateUserDisplayNameByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/UpdateUserDisplayNameByAdmin.graphql new file mode 100644 index 0000000000..5776dc3977 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/UpdateUserDisplayNameByAdmin.graphql @@ -0,0 +1,3 @@ +mutation UpdateUserDisplayNameByAdmin($userUID: ID!, $name: String!) { + updateUserDisplayNameByAdmin(userUID: $userUID, displayName: $name) +} diff --git a/packages/hoppscotch-sh-admin/src/pages/users/_id.vue b/packages/hoppscotch-sh-admin/src/pages/users/_id.vue index 11090138ed..8d7acdae6d 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/_id.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/_id.vue @@ -12,7 +12,7 @@

- {{ user.displayName }} + {{ userName }}

/

@@ -29,6 +29,7 @@ @delete-user="deleteUser" @make-admin="makeUserAdmin" @remove-admin="makeAdminToUser" + @update-user-name="(name: string) => (userName = name)" class="py-8 px-4" /> @@ -40,19 +41,19 @@ @@ -104,6 +105,15 @@ onMounted(async () => { await fetchData(); }); +const userName = computed({ + get: () => data.value?.infra.userInfo.displayName, + set: (value) => { + if (value) { + data.value!.infra.userInfo.displayName = value; + } + }, +}); + const user = computed({ get: () => data.value?.infra.userInfo, set: (value) => { From c1d3e06c8ca48912b1fc50ee881db5144597f8e6 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:20:12 +0530 Subject: [PATCH 13/60] refactor: updated i18n strings --- packages/hoppscotch-sh-admin/locales/en.json | 11 +++++++++++ .../hoppscotch-sh-admin/src/pages/users/index.vue | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/hoppscotch-sh-admin/locales/en.json b/packages/hoppscotch-sh-admin/locales/en.json index cfaf128889..cb1fbbc383 100644 --- a/packages/hoppscotch-sh-admin/locales/en.json +++ b/packages/hoppscotch-sh-admin/locales/en.json @@ -163,8 +163,15 @@ "remove_invitee_success": "Removal of invitee is successfull!!", "remove_member_failure": "Member couldn't be removed!!", "remove_member_success": "Member removed successfully!!", +<<<<<<< HEAD "rename_team_failure": "Failed to rename workspace!!", "rename_team_success": "Workspace renamed successfully!", +======= + "rename_team_failure": "Failed to rename team!!", + "rename_team_success": "Team renamed successfully!", + "rename_user_failure": "Failed to rename user!!", + "rename_user_success": "User renamed successfully!!", +>>>>>>> 75ca9848 (refactor: updated i18n strings) "require_auth_provider": "You need to set atleast one authentication provider to log in.", "role_update_failed": "Roles updation has failed!!", "role_update_success": "Roles updated successfully!!", @@ -243,13 +250,16 @@ "admin": "Admin", "admin_email": "Admin Email", "admin_id": "Admin ID", + "created_on": "Created On", "date": "Date", "delete": "Delete", "delete_user": "Delete User", "delete_users": "Delete Users", "details": "Details", + "edit": "Edit", "email": "Email", "email_address": "Email Address", + "empty_name": "Name cannot be empty!!", "id": "User ID", "invalid_user": "Invalid User", "invite_load_list_error": "Unable to Load Invited Users List", @@ -268,6 +278,7 @@ "pending_invites": "Pending Invites", "remove_admin_privilege": "Remove Admin Privilege", "remove_admin_status": "Remove Admin Status", + "rename": "Rename", "searchbar_placeholder": "Search by name or email..", "send_invite": "Send Invite", "show_more": "Show more", diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index c5f9859afa..4f3d906d20 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -277,7 +277,6 @@ const { const selectedRows = ref([]); // Search - const searchQuery = ref(''); const handleInput = async (input: string) => { searchQuery.value = input; From 0818eb17ebc89d5051aaec7f2204f79b6324f4a9 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:32:18 +0530 Subject: [PATCH 14/60] chore: cleaned up code in details component --- packages/hoppscotch-sh-admin/locales/en.json | 5 --- .../src/components/users/Details.vue | 40 +++++++++---------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/packages/hoppscotch-sh-admin/locales/en.json b/packages/hoppscotch-sh-admin/locales/en.json index cb1fbbc383..da7db24f54 100644 --- a/packages/hoppscotch-sh-admin/locales/en.json +++ b/packages/hoppscotch-sh-admin/locales/en.json @@ -163,15 +163,10 @@ "remove_invitee_success": "Removal of invitee is successfull!!", "remove_member_failure": "Member couldn't be removed!!", "remove_member_success": "Member removed successfully!!", -<<<<<<< HEAD "rename_team_failure": "Failed to rename workspace!!", "rename_team_success": "Workspace renamed successfully!", -======= - "rename_team_failure": "Failed to rename team!!", - "rename_team_success": "Team renamed successfully!", "rename_user_failure": "Failed to rename user!!", "rename_user_success": "User renamed successfully!!", ->>>>>>> 75ca9848 (refactor: updated i18n strings) "require_auth_provider": "You need to set atleast one authentication provider to log in.", "role_update_failed": "Roles updation has failed!!", "role_update_success": "Roles updated successfully!!", diff --git a/packages/hoppscotch-sh-admin/src/components/users/Details.vue b/packages/hoppscotch-sh-admin/src/components/users/Details.vue index df468739c0..fe1ffbd01b 100644 --- a/packages/hoppscotch-sh-admin/src/components/users/Details.vue +++ b/packages/hoppscotch-sh-admin/src/components/users/Details.vue @@ -24,10 +24,7 @@

@@ -104,20 +99,20 @@ diff --git a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue index 66bec95cd1..41802a7fbd 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue @@ -119,18 +119,18 @@ const deleteInvite = (inviteeEmail: string) => { const deleteUserInvitation = async (inviteeEmail: string | null) => { if (!inviteeEmail) { confirmDeletion.value = false; - toast.error(t('state.delete_invites_failure')); + toast.error(t('state.delete_invite_failure')); return; } const variables = { inviteeEmail }; const result = await deleteInvitationMutation.executeMutation(variables); if (result.error) { - toast.error(t('state.delete_invites_failure')); + toast.error(t('state.delete_invite_failure')); } else { invitedUsers.value = invitedUsers.value?.filter( (request) => request.inviteeEmail !== inviteeEmail ); - toast.success(t('state.delete_invites_success')); + toast.success(t('state.delete_invite_success')); } confirmDeletion.value = false; From 8510e64a9f6b2076bccc4ab3599403e8b24dc61c Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:42:24 +0530 Subject: [PATCH 20/60] refactor: updated mutations to adhere to the new format introduced in the backend --- .../helpers/backend/gql/mutations/DemoteUsersByAdmin.graphql | 3 +++ .../helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql | 3 --- .../helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql | 2 +- .../backend/gql/mutations/RevokeUserInvitationByAdmin.graphql | 3 --- .../backend/gql/mutations/RevokeUserInvitationsByAdmin.graphql | 3 +++ 5 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/DemoteUsersByAdmin.graphql delete mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql delete mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationByAdmin.graphql create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationsByAdmin.graphql diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/DemoteUsersByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/DemoteUsersByAdmin.graphql new file mode 100644 index 0000000000..b91992ce0f --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/DemoteUsersByAdmin.graphql @@ -0,0 +1,3 @@ +mutation DemoteUsersByAdmin($userUIDs: [ID!]!) { + demoteUsersByAdmin(userUIDs: $userUIDs) +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql deleted file mode 100644 index a37bafdf80..0000000000 --- a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersAsAdmin.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation RemoveUsersAsAdmin($userUIDs: [ID!]!) { - removeUsersAsAdmin(userUIDs: $userUIDs) -} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql index 7933f1a5e8..d3649e5f5f 100644 --- a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUsersByAdmin.graphql @@ -1,7 +1,7 @@ mutation RemoveUsersByAdmin($userUIDs: [ID!]!) { removeUsersByAdmin(userUIDs: $userUIDs) { userUID - success + isDeleted errorMessage } } diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationByAdmin.graphql deleted file mode 100644 index 2a16e9978d..0000000000 --- a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationByAdmin.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation RevokeUserInvitationByAdmin($inviteeEmail: ID!) { - revokeUserInvitationByAdmin(inviteeEmail: $inviteeEmail) -} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationsByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationsByAdmin.graphql new file mode 100644 index 0000000000..98ccac4c71 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeUserInvitationsByAdmin.graphql @@ -0,0 +1,3 @@ +mutation RevokeUserInvitationsByAdmin($inviteeEmails: [String!]!) { + revokeUserInvitationsByAdmin(inviteeEmails: $inviteeEmails) +} From fbe83104722c5abe545adecf3f8d3b682ed4db4e Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:52:42 +0530 Subject: [PATCH 21/60] refactor: updated invited component to adhere to the new backend changes --- packages/hoppscotch-sh-admin/src/pages/users/invited.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue index 41802a7fbd..7aa67d3d68 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue @@ -66,7 +66,7 @@ import { computed, ref } from 'vue'; import { useQuery, useMutation } from '@urql/vue'; import { InvitedUsersDocument, - RevokeUserInvitationByAdminDocument, + RevokeUserInvitationsByAdminDocument, } from '../../helpers/backend/graphql'; import { format } from 'date-fns'; import { useRouter } from 'vue-router'; @@ -108,7 +108,7 @@ const invitedUsers = computed({ const confirmDeletion = ref(false); const inviteToBeDeleted = ref(null); const deleteInvitationMutation = useMutation( - RevokeUserInvitationByAdminDocument + RevokeUserInvitationsByAdminDocument ); const deleteInvite = (inviteeEmail: string) => { @@ -122,7 +122,7 @@ const deleteUserInvitation = async (inviteeEmail: string | null) => { toast.error(t('state.delete_invite_failure')); return; } - const variables = { inviteeEmail }; + const variables = { inviteeEmails: [inviteeEmail] }; const result = await deleteInvitationMutation.executeMutation(variables); if (result.error) { toast.error(t('state.delete_invite_failure')); From 5d496a638bf659414868b04999028c350df800d5 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:53:42 +0530 Subject: [PATCH 22/60] refactor: updated make users to admin and remove admin status to use only specific mutation each --- .../src/pages/users/index.vue | 234 +++++++++--------- 1 file changed, 116 insertions(+), 118 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 881ef9dd0a..70437365d9 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -103,8 +103,8 @@ @click=" () => { user.isAdmin - ? makeAdminToUser(user.uid) - : makeUserAdmin(user.uid); + ? makeAdminsUsers(user.uid) + : makeUsersAdmin(user.uid); hide(); } " @@ -175,29 +175,25 @@ @hide-modal="confirmDeletion = false" @resolve="deleteUserMutation(deleteUserUID)" /> - - { } }; -// Make a single user an admin -const userToAdmin = useMutation(MakeUserAdminDocument); -const confirmUserToAdmin = ref(false); -const userToAdminUID = ref(null); - -const makeUserAdmin = (id: string) => { - confirmUserToAdmin.value = true; - userToAdminUID.value = id; -}; - -const makeUserAdminMutation = async (id: string | null) => { - if (!id) { - confirmUserToAdmin.value = false; - toast.error(t('state.admin_failure')); - return; - } - const variables = { uid: id }; - const result = await userToAdmin.executeMutation(variables); - if (result.error) { - toast.error(t('state.admin_failure')); - } else { - toast.success(t('state.admin_success')); - usersList.value = usersList.value.map((user) => ({ - ...user, - isAdmin: user.uid === id ? true : user.isAdmin, - })); - } - confirmUserToAdmin.value = false; - userToAdminUID.value = null; -}; - // Remove Admin Status from a Current Admin -const adminToUser = useMutation(RemoveUserAsAdminDocument); -const confirmAdminToUser = ref(false); -const adminToUserUID = ref(null); - -const makeAdminToUser = (id: string) => { - confirmAdminToUser.value = true; - adminToUserUID.value = id; -}; - -const makeAdminToUserMutation = async (id: string | null) => { - if (!id) { - confirmAdminToUser.value = false; - toast.error(t('state.remove_admin_failure')); - return; - } - const variables = { uid: id }; - const result = await adminToUser.executeMutation(variables); - if (result.error) { - toast.error(t('state.remove_admin_failure')); - } else { - toast.success(t('state.remove_admin_success')); - usersList.value = usersList.value.map((user) => ({ - ...user, - isAdmin: user.uid === id ? false : user.isAdmin, - })); - } - confirmAdminToUser.value = false; - adminToUserUID.value = null; -}; +// const adminToUser = useMutation(RemoveUserAsAdminDocument); +// const confirmAdminToUser = ref(false); +// const adminToUserUID = ref(null); + +// const makeAdminToUser = (id: string) => { +// confirmAdminToUser.value = true; +// adminToUserUID.value = id; +// }; + +// const makeAdminToUserMutation = async (id: string | null) => { +// if (!id) { +// confirmAdminToUser.value = false; +// toast.error(t('state.remove_admin_failure')); +// return; +// } +// const variables = { uid: id }; +// const result = await adminToUser.executeMutation(variables); +// if (result.error) { +// toast.error(t('state.remove_admin_failure')); +// } else { +// toast.success(t('state.remove_admin_success')); +// usersList.value = usersList.value.map((user) => ({ +// ...user, +// isAdmin: user.uid === id ? false : user.isAdmin, +// })); +// } +// confirmAdminToUser.value = false; +// adminToUserUID.value = null; +// }; // Delete a single user -const userDeletion = useMutation(RemoveUserByAdminDocument); -const confirmDeletion = ref(false); -const deleteUserUID = ref(null); - -const deleteUser = (id: string) => { - confirmDeletion.value = true; - deleteUserUID.value = id; -}; - -const deleteUserMutation = async (id: string | null) => { - if (!id) { - confirmDeletion.value = false; - toast.error(t('state.delete_user_failure')); - return; - } - const variables = { uid: id }; - const result = await userDeletion.executeMutation(variables); - if (result.error) { - if (result.error.message === DELETE_USER_FAILED_ONLY_ONE_ADMIN) { - toast.error(t('state.delete_user_failed_only_one_admin')); - } else toast.error(t('state.delete_user_failure')); - } else { - toast.success(t('state.delete_user_success')); - usersList.value = usersList.value.filter((user) => user.uid !== id); - } - confirmDeletion.value = false; - deleteUserUID.value = null; -}; +// const userDeletion = useMutation(RemoveUserByAdminDocument); +// const confirmDeletion = ref(false); +// const deleteUserUID = ref(null); + +// const deleteUser = (id: string) => { +// confirmDeletion.value = true; +// deleteUserUID.value = id; +// }; + +// const deleteUserMutation = async (id: string | null) => { +// if (!id) { +// confirmDeletion.value = false; +// toast.error(t('state.delete_user_failure')); +// return; +// } +// const variables = { uid: id }; +// const result = await userDeletion.executeMutation(variables); +// if (result.error) { +// if (result.error.message === DELETE_USER_FAILED_ONLY_ONE_ADMIN) { +// toast.error(t('state.delete_user_failed_only_one_admin')); +// } else toast.error(t('state.delete_user_failure')); +// } else { +// toast.success(t('state.delete_user_success')); +// usersList.value = usersList.value.filter((user) => user.uid !== id); +// } +// confirmDeletion.value = false; +// deleteUserUID.value = null; +// }; // Make Multiple Users Admin -const usersToAdmin = useMutation(MakeUsersAdminDocument); const confirmUsersToAdmin = ref(false); +const usersToAdminUID = ref(null); +const usersToAdmin = useMutation(MakeUsersAdminDocument); -const makeUsersToAdmin = async () => { - const userUIDs = selectedRows.value.map((user) => user.uid); +const AreMultipleUsersSelected = computed( + () => usersToAdminUID.value === null && selectedRows.value.length > 0 +); + +const makeUsersAdmin = (id: string | null) => { + confirmUsersToAdmin.value = true; + usersToAdminUID.value = id; +}; +const makeUsersToAdmin = async (id: string | null) => { + const userUIDs = id ? [id] : selectedRows.value.map((user) => user.uid); const variables = { userUIDs }; const result = await usersToAdmin.executeMutation(variables); + if (result.error) { - toast.error(t('state.users_to_admin_failure')); + toast.error( + id ? t('state.admin_failure') : t('state.users_to_admin_failure') + ); } else { - toast.success(t('state.users_to_admin_success')); + toast.success( + id ? t('state.admin_success') : t('state.users_to_admin_success') + ); usersList.value = usersList.value.map((user) => ({ ...user, isAdmin: userUIDs.includes(user.uid) ? true : user.isAdmin, @@ -439,21 +417,40 @@ const makeUsersToAdmin = async () => { selectedRows.value.splice(0, selectedRows.value.length); } confirmUsersToAdmin.value = false; + usersToAdminUID.value = null; }; // Remove Admin Status from Multiple Users -const adminsToUser = useMutation(RemoveUsersAsAdminDocument); +const adminsToUser = useMutation(DemoteUsersByAdminDocument); const confirmAdminsToUsers = ref(false); +const adminsToUserUID = ref(null); -const makeAdminsToUsers = async () => { - const userUIDs = selectedRows.value.map((user) => user.uid); +const makeAdminsUsers = (id: string | null) => { + confirmAdminsToUsers.value = true; + adminsToUserUID.value = id; +}; + +const AreMultipleUsersSelectedToAdmin = computed( + () => adminsToUserUID.value === null && selectedRows.value.length > 0 +); + +const makeAdminsToUsers = async (id: string | null) => { + const userUIDs = id ? [id] : selectedRows.value.map((user) => user.uid); const variables = { userUIDs }; const result = await adminsToUser.executeMutation(variables); if (result.error) { - toast.error(t('state.remove_admin_from_users_failure')); + toast.error( + id + ? t('state.remove_admin_failure') + : t('state.remove_admin_from_users_failure') + ); } else { - toast.success(t('state.remove_admin_from_users_success')); + toast.success( + id + ? t('state.remove_admin_success') + : t('state.remove_admin_from_users_success') + ); usersList.value = usersList.value.map((user) => ({ ...user, isAdmin: userUIDs.includes(user.uid) ? false : user.isAdmin, @@ -462,6 +459,7 @@ const makeAdminsToUsers = async () => { selectedRows.value.splice(0, selectedRows.value.length); } confirmAdminsToUsers.value = false; + adminsToUserUID.value = null; }; // Delete Multiple Users From f75106772faa359ed0bd633a74d12b6257a25416 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:55:16 +0530 Subject: [PATCH 23/60] refactor: removed decprecated mutations --- .../src/helpers/backend/gql/mutations/MakeUserAdmin.graphql | 3 --- .../helpers/backend/gql/mutations/RemoveUserAsAdmin.graphql | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUserAdmin.graphql delete mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserAsAdmin.graphql diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUserAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUserAdmin.graphql deleted file mode 100644 index 89c31c37f1..0000000000 --- a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/MakeUserAdmin.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation MakeUserAdmin($uid: ID!) { - makeUserAdmin(userUID: $uid) -} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserAsAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserAsAdmin.graphql deleted file mode 100644 index 3fc2374bb3..0000000000 --- a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserAsAdmin.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation RemoveUserAsAdmin($uid: ID!) { - removeUserAsAdmin(userUID: $uid) -} From 5bb5fbf477bac6f65ad045cd5e11475681a37524 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 12:04:27 +0530 Subject: [PATCH 24/60] refactor: updated deletion of users operation to use only one mutation --- .../gql/mutations/RemoveUserByAdmin.graphql | 3 - .../src/pages/users/index.vue | 104 +++++------------- 2 files changed, 29 insertions(+), 78 deletions(-) delete mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserByAdmin.graphql diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserByAdmin.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserByAdmin.graphql deleted file mode 100644 index 2ee09541ff..0000000000 --- a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveUserByAdmin.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation RemoveUserByAdmin($uid: ID!) { - removeUserByAdmin(userUID: $uid) -} diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 70437365d9..c68e2dfc15 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -169,12 +169,6 @@ @hide-modal="showInviteUserModal = false" @send-invite="sendInvite" /> -
@@ -217,8 +215,6 @@ import { InviteNewUserDocument, MakeUsersAdminDocument, MetricsDocument, - RemoveUserAsAdminDocument, - RemoveUserByAdminDocument, RemoveUsersByAdminDocument, UserInfoQuery, UsersListQuery, @@ -322,67 +318,6 @@ const sendInvite = async (email: string) => { } }; -// Remove Admin Status from a Current Admin -// const adminToUser = useMutation(RemoveUserAsAdminDocument); -// const confirmAdminToUser = ref(false); -// const adminToUserUID = ref(null); - -// const makeAdminToUser = (id: string) => { -// confirmAdminToUser.value = true; -// adminToUserUID.value = id; -// }; - -// const makeAdminToUserMutation = async (id: string | null) => { -// if (!id) { -// confirmAdminToUser.value = false; -// toast.error(t('state.remove_admin_failure')); -// return; -// } -// const variables = { uid: id }; -// const result = await adminToUser.executeMutation(variables); -// if (result.error) { -// toast.error(t('state.remove_admin_failure')); -// } else { -// toast.success(t('state.remove_admin_success')); -// usersList.value = usersList.value.map((user) => ({ -// ...user, -// isAdmin: user.uid === id ? false : user.isAdmin, -// })); -// } -// confirmAdminToUser.value = false; -// adminToUserUID.value = null; -// }; - -// Delete a single user -// const userDeletion = useMutation(RemoveUserByAdminDocument); -// const confirmDeletion = ref(false); -// const deleteUserUID = ref(null); - -// const deleteUser = (id: string) => { -// confirmDeletion.value = true; -// deleteUserUID.value = id; -// }; - -// const deleteUserMutation = async (id: string | null) => { -// if (!id) { -// confirmDeletion.value = false; -// toast.error(t('state.delete_user_failure')); -// return; -// } -// const variables = { uid: id }; -// const result = await userDeletion.executeMutation(variables); -// if (result.error) { -// if (result.error.message === DELETE_USER_FAILED_ONLY_ONE_ADMIN) { -// toast.error(t('state.delete_user_failed_only_one_admin')); -// } else toast.error(t('state.delete_user_failure')); -// } else { -// toast.success(t('state.delete_user_success')); -// usersList.value = usersList.value.filter((user) => user.uid !== id); -// } -// confirmDeletion.value = false; -// deleteUserUID.value = null; -// }; - // Make Multiple Users Admin const confirmUsersToAdmin = ref(false); const usersToAdminUID = ref(null); @@ -465,21 +400,40 @@ const makeAdminsToUsers = async (id: string | null) => { // Delete Multiple Users const usersDeletion = useMutation(RemoveUsersByAdminDocument); const confirmUsersDeletion = ref(false); +const deleteUserUID = ref(null); + +const deleteUser = (id: string | null) => { + confirmUsersDeletion.value = true; + deleteUserUID.value = id; +}; + +const AreMultipleUsersSelectedForDeletion = computed( + () => deleteUserUID.value === null && selectedRows.value.length > 0 +); -const deleteUsers = async () => { - const userUIDs = selectedRows.value.map((user) => user.uid); +const deleteUsers = async (id: string | null) => { + const userUIDs = id ? [id] : selectedRows.value.map((user) => user.uid); const variables = { userUIDs }; const result = await usersDeletion.executeMutation(variables); if (result.error) { - toast.error(t('state.delete_users_failure')); + if (result.error.message === DELETE_USER_FAILED_ONLY_ONE_ADMIN) { + toast.error(t('state.delete_user_failed_only_one_admin')); + } else { + toast.error( + id ? t('state.delete_user_failure') : t('state.delete_users_failure') + ); + } } else { - toast.success(t('state.delete_user_success')); + toast.success( + id ? t('state.delete_user_success') : t('state.delete_users_success') + ); usersList.value = usersList.value.filter( (user) => !userUIDs.includes(user.uid) ); selectedRows.value.splice(0, selectedRows.value.length); } confirmUsersDeletion.value = false; + deleteUserUID.value = null; }; From 2b4d08dee113fd80d6da68672eabc8098dd4ec80 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:30:48 +0530 Subject: [PATCH 25/60] style: removed padding for shared request error message --- .../hoppscotch-sh-admin/src/components/users/SharedRequests.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hoppscotch-sh-admin/src/components/users/SharedRequests.vue b/packages/hoppscotch-sh-admin/src/components/users/SharedRequests.vue index 9c8b36ef12..4d3bb0407f 100644 --- a/packages/hoppscotch-sh-admin/src/components/users/SharedRequests.vue +++ b/packages/hoppscotch-sh-admin/src/components/users/SharedRequests.vue @@ -6,7 +6,7 @@
{{ t('shared_requests.load_list_error') }}
-
+
{{ t('users.no_shared_requests') }}
From c118393d07d2846a3c9378169512c472860dcb3f Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:33:08 +0530 Subject: [PATCH 26/60] refactor: deletion of a single user now uses the new mutation --- .../src/pages/users/index.vue | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index c68e2dfc15..f73c7bf40c 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -413,24 +413,46 @@ const AreMultipleUsersSelectedForDeletion = computed( const deleteUsers = async (id: string | null) => { const userUIDs = id ? [id] : selectedRows.value.map((user) => user.uid); - const variables = { userUIDs }; const result = await usersDeletion.executeMutation(variables); + if (result.error) { - if (result.error.message === DELETE_USER_FAILED_ONLY_ONE_ADMIN) { - toast.error(t('state.delete_user_failed_only_one_admin')); - } else { - toast.error( - id ? t('state.delete_user_failure') : t('state.delete_users_failure') - ); - } + const errorMessage = + result.error.message === DELETE_USER_FAILED_ONLY_ONE_ADMIN + ? t('state.delete_user_failed_only_one_admin') + : id + ? t('state.delete_user_failure') + : t('state.delete_users_failure'); + toast.error(errorMessage); } else { - toast.success( - id ? t('state.delete_user_success') : t('state.delete_users_success') + const deletedUsers = result.data?.removeUsersByAdmin || []; + const deletedIDs = deletedUsers + .filter((user) => user.isDeleted) + .map((user) => user.userUID); + + const isAdminError = deletedUsers.some( + (user) => user.errorMessage === 'admin/admin_can_not_be_deleted' ); + usersList.value = usersList.value.filter( - (user) => !userUIDs.includes(user.uid) + (user) => !deletedIDs.includes(user.uid) ); + + if (isAdminError) { + toast.success( + `Number of Users Deleted Successfully: ${deletedIDs.length}` + ); + toast.error( + `Users Not Deleted Due to Admin Status: ${ + deletedUsers.length - deletedIDs.length + }. \nPlease remove admin status before deleting users` + ); + } else { + toast.success( + id ? t('state.delete_user_success') : t('state.delete_users_success') + ); + } + selectedRows.value.splice(0, selectedRows.value.length); } confirmUsersDeletion.value = false; From 1e3272fce517c7c311eee90325833009f023a615 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:40:35 +0530 Subject: [PATCH 27/60] refactor: updated styles and i18n strings in invited components --- packages/hoppscotch-sh-admin/locales/en.json | 2 +- packages/hoppscotch-sh-admin/src/pages/users/invited.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hoppscotch-sh-admin/locales/en.json b/packages/hoppscotch-sh-admin/locales/en.json index 8f59704d9d..ff1e3bed2a 100644 --- a/packages/hoppscotch-sh-admin/locales/en.json +++ b/packages/hoppscotch-sh-admin/locales/en.json @@ -269,7 +269,7 @@ "load_list_error": "Unable to Load Users List", "make_admin": "Make Admin", "name": "Name", - "no_invite": "No invited users found", + "no_invite": "No pending invites found", "no_shared_requests": "No shared requests created by the user", "no_users": "No users found", "not_found": "User not found", diff --git a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue index 7aa67d3d68..2583e8a8eb 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue @@ -16,7 +16,7 @@
-
+
{{ t('users.invite_load_list_error') }}
@@ -49,7 +49,7 @@ -
{{ t('users.no_invite') }}
+
{{ t('users.no_invite') }}
Date: Tue, 13 Feb 2024 18:42:07 +0530 Subject: [PATCH 28/60] refactor: updated individual user components to adhere to the new backend changes --- .../src/pages/users/_id.vue | 98 +++++++++++-------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/_id.vue b/packages/hoppscotch-sh-admin/src/pages/users/_id.vue index 8d7acdae6d..162875a73b 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/_id.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/_id.vue @@ -68,9 +68,9 @@ import { useI18n } from '~/composables/i18n'; import { useToast } from '~/composables/toast'; import { useClientHandler } from '~/composables/useClientHandler'; import { - MakeUserAdminDocument, - RemoveUserAsAdminDocument, - RemoveUserByAdminDocument, + DemoteUsersByAdminDocument, + MakeUsersAdminDocument, + RemoveUsersByAdminDocument, UserInfoDocument, } from '~/helpers/backend/graphql'; @@ -123,43 +123,11 @@ const user = computed({ }, }); -// User Deletion -const router = useRouter(); -const userDeletion = useMutation(RemoveUserByAdminDocument); -const confirmDeletion = ref(false); -const deleteUserUID = ref(null); - -const deleteUser = (id: string) => { - confirmDeletion.value = true; - deleteUserUID.value = id; -}; - -const deleteUserMutation = async (id: string | null) => { - if (!id) { - confirmDeletion.value = false; - toast.error(t('state.delete_user_failure')); - return; - } - const variables = { uid: id }; - const result = await userDeletion.executeMutation(variables); - - if (result.error) { - toast.error(t('state.delete_user_failure')); - } else { - toast.success(t('state.delete_user_success')); - } - - confirmDeletion.value = false; - deleteUserUID.value = null; - router.push('/users'); -}; - -// Make User Admin -const userToAdmin = useMutation(MakeUserAdminDocument); const confirmUserToAdmin = ref(false); const userToAdminUID = ref(null); +const usersToAdmin = useMutation(MakeUsersAdminDocument); -const makeUserAdmin = (id: string) => { +const makeUserAdmin = (id: string | null) => { confirmUserToAdmin.value = true; userToAdminUID.value = id; }; @@ -170,20 +138,23 @@ const makeUserAdminMutation = async (id: string | null) => { toast.error(t('state.admin_failure')); return; } - const variables = { uid: id }; - const result = await userToAdmin.executeMutation(variables); + + const userUIDs = [id]; + const variables = { userUIDs }; + const result = await usersToAdmin.executeMutation(variables); + if (result.error) { toast.error(t('state.admin_failure')); } else { - user.value!.isAdmin = true; toast.success(t('state.admin_success')); + user.value!.isAdmin = true; } confirmUserToAdmin.value = false; userToAdminUID.value = null; }; // Remove Admin Status from a current admin user -const adminToUser = useMutation(RemoveUserAsAdminDocument); +const adminToUser = useMutation(DemoteUsersByAdminDocument); const confirmAdminToUser = ref(false); const adminToUserUID = ref(null); @@ -198,15 +169,56 @@ const makeAdminToUserMutation = async (id: string | null) => { toast.error(t('state.remove_admin_failure')); return; } - const variables = { uid: id }; + + const userUIDs = [id]; + const variables = { userUIDs }; const result = await adminToUser.executeMutation(variables); if (result.error) { toast.error(t('state.remove_admin_failure')); } else { + toast.success(t('state.remove_admin_success')); user.value!.isAdmin = false; - toast.error(t('state.remove_admin_success')); } confirmAdminToUser.value = false; adminToUserUID.value = null; }; + +// User Deletion +const router = useRouter(); +const userDeletion = useMutation(RemoveUsersByAdminDocument); +const confirmDeletion = ref(false); +const deleteUserUID = ref(null); + +const deleteUser = (id: string) => { + confirmDeletion.value = true; + deleteUserUID.value = id; +}; + +const deleteUserMutation = async (id: string | null) => { + if (!id) { + confirmDeletion.value = false; + toast.error(t('state.delete_user_failure')); + return; + } + const userUIDs = [id]; + const variables = { userUIDs }; + const result = await userDeletion.executeMutation(variables); + + if (result.error) { + toast.error(t('state.delete_user_failure')); + } else { + const deletedUsers = result.data?.removeUsersByAdmin || []; + + const isAdminError = deletedUsers.some( + (user) => user.errorMessage === 'admin/admin_can_not_be_deleted' + ); + + isAdminError + ? toast.error(t('state.delete_user_failed_only_one_admin')) + : toast.success(t('state.delete_user_success')); + } + confirmDeletion.value = false; + deleteUserUID.value = null; + router.push('/users'); +}; From 42a2e37183f9041a952a53c043c44e91c76ae6be Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Wed, 14 Feb 2024 09:31:21 +0530 Subject: [PATCH 29/60] feat: added spinner functionality to the users table --- .../src/components/users/Table.vue | 52 ++++++++++++------- .../src/pages/users/index.vue | 2 + 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/components/users/Table.vue b/packages/hoppscotch-sh-admin/src/components/users/Table.vue index 5edde47f7e..a5095c1639 100644 --- a/packages/hoppscotch-sh-admin/src/components/users/Table.vue +++ b/packages/hoppscotch-sh-admin/src/components/users/Table.vue @@ -100,7 +100,7 @@ From 29cc15bf529b1ab200dd1d2cc22e9a27d6f9ee29 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Thu, 29 Feb 2024 12:52:42 +0530 Subject: [PATCH 40/60] refactor: updated users table to adhere to removal of search and debouncer feature from smart table --- .../src/pages/users/index.vue | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index d0736e8a07..b987cb1436 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -28,17 +28,23 @@ :headings="headings" :list="usersList" :checkbox="true" + :spinner="showSpinner" :selected-rows="selectedRows" - :search-bar="{ - debounce: 500, - placeholder: t('users.searchbar_placeholder'), - }" - :spinner="{ enabled: fetching, duration: 500 }" - :pagination="{ totalPages: totalPages }" - @onRowClicked="goToUserDetails" - @search="handleSearch" + :pagination="{ totalPages }" @pageNumber="handlePageChange" + @onRowClicked="goToUserDetails" > + + + - +
-
- +
Date: Fri, 8 Mar 2024 09:18:34 +0530 Subject: [PATCH 49/60] chore: component fixes --- .../hoppscotch-common/src/components.d.ts | 416 +++++++++--------- 1 file changed, 208 insertions(+), 208 deletions(-) diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts index df8e8a8fa7..20783de26a 100644 --- a/packages/hoppscotch-common/src/components.d.ts +++ b/packages/hoppscotch-common/src/components.d.ts @@ -1,214 +1,214 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// Generated by unplugin-vue-components +// 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" + export {} -declare module 'vue' { +declare module "@vue/runtime-core" { export interface GlobalComponents { - AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default'] - AppBanner: typeof import('./components/app/Banner.vue')['default'] - AppContextMenu: typeof import('./components/app/ContextMenu.vue')['default'] - AppDeveloperOptions: typeof import('./components/app/DeveloperOptions.vue')['default'] - AppFooter: typeof import('./components/app/Footer.vue')['default'] - AppGitHubStarButton: typeof import('./components/app/GitHubStarButton.vue')['default'] - AppHeader: typeof import('./components/app/Header.vue')['default'] - AppInspection: typeof import('./components/app/Inspection.vue')['default'] - AppInterceptor: typeof import('./components/app/Interceptor.vue')['default'] - AppLogo: typeof import('./components/app/Logo.vue')['default'] - AppOptions: typeof import('./components/app/Options.vue')['default'] - AppPaneLayout: typeof import('./components/app/PaneLayout.vue')['default'] - AppShare: typeof import('./components/app/Share.vue')['default'] - AppShortcuts: typeof import('./components/app/Shortcuts.vue')['default'] - AppShortcutsEntry: typeof import('./components/app/ShortcutsEntry.vue')['default'] - AppShortcutsPrompt: typeof import('./components/app/ShortcutsPrompt.vue')['default'] - AppSidenav: typeof import('./components/app/Sidenav.vue')['default'] - AppSpotlight: typeof import('./components/app/spotlight/index.vue')['default'] - AppSpotlightEntry: typeof import('./components/app/spotlight/Entry.vue')['default'] - AppSpotlightEntryGQLHistory: typeof import('./components/app/spotlight/entry/GQLHistory.vue')['default'] - AppSpotlightEntryGQLRequest: typeof import('./components/app/spotlight/entry/GQLRequest.vue')['default'] - AppSpotlightEntryIconSelected: typeof import('./components/app/spotlight/entry/IconSelected.vue')['default'] - AppSpotlightEntryRESTHistory: typeof import('./components/app/spotlight/entry/RESTHistory.vue')['default'] - AppSpotlightEntryRESTRequest: typeof import('./components/app/spotlight/entry/RESTRequest.vue')['default'] - AppSupport: typeof import('./components/app/Support.vue')['default'] - Collections: typeof import('./components/collections/index.vue')['default'] - CollectionsAdd: typeof import('./components/collections/Add.vue')['default'] - CollectionsAddFolder: typeof import('./components/collections/AddFolder.vue')['default'] - CollectionsAddRequest: typeof import('./components/collections/AddRequest.vue')['default'] - CollectionsCollection: typeof import('./components/collections/Collection.vue')['default'] - CollectionsEdit: typeof import('./components/collections/Edit.vue')['default'] - CollectionsEditFolder: typeof import('./components/collections/EditFolder.vue')['default'] - CollectionsEditRequest: typeof import('./components/collections/EditRequest.vue')['default'] - CollectionsGraphql: typeof import('./components/collections/graphql/index.vue')['default'] - CollectionsGraphqlAdd: typeof import('./components/collections/graphql/Add.vue')['default'] - CollectionsGraphqlAddFolder: typeof import('./components/collections/graphql/AddFolder.vue')['default'] - CollectionsGraphqlAddRequest: typeof import('./components/collections/graphql/AddRequest.vue')['default'] - CollectionsGraphqlCollection: typeof import('./components/collections/graphql/Collection.vue')['default'] - CollectionsGraphqlEdit: typeof import('./components/collections/graphql/Edit.vue')['default'] - CollectionsGraphqlEditFolder: typeof import('./components/collections/graphql/EditFolder.vue')['default'] - CollectionsGraphqlEditRequest: typeof import('./components/collections/graphql/EditRequest.vue')['default'] - CollectionsGraphqlFolder: typeof import('./components/collections/graphql/Folder.vue')['default'] - CollectionsGraphqlImportExport: typeof import('./components/collections/graphql/ImportExport.vue')['default'] - CollectionsGraphqlRequest: typeof import('./components/collections/graphql/Request.vue')['default'] - CollectionsImportExport: typeof import('./components/collections/ImportExport.vue')['default'] - CollectionsMyCollections: typeof import('./components/collections/MyCollections.vue')['default'] - CollectionsProperties: typeof import('./components/collections/Properties.vue')['default'] - CollectionsRequest: typeof import('./components/collections/Request.vue')['default'] - CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default'] - CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default'] - CookiesAllModal: typeof import('./components/cookies/AllModal.vue')['default'] - CookiesEditCookie: typeof import('./components/cookies/EditCookie.vue')['default'] - Embeds: typeof import('./components/embeds/index.vue')['default'] - Environments: typeof import('./components/environments/index.vue')['default'] - EnvironmentsAdd: typeof import('./components/environments/Add.vue')['default'] - EnvironmentsImportExport: typeof import('./components/environments/ImportExport.vue')['default'] - EnvironmentsMy: typeof import('./components/environments/my/index.vue')['default'] - EnvironmentsMyDetails: typeof import('./components/environments/my/Details.vue')['default'] - EnvironmentsMyEnvironment: typeof import('./components/environments/my/Environment.vue')['default'] - EnvironmentsSelector: typeof import('./components/environments/Selector.vue')['default'] - EnvironmentsTeams: typeof import('./components/environments/teams/index.vue')['default'] - EnvironmentsTeamsDetails: typeof import('./components/environments/teams/Details.vue')['default'] - EnvironmentsTeamsEnvironment: typeof import('./components/environments/teams/Environment.vue')['default'] - FirebaseLogin: typeof import('./components/firebase/Login.vue')['default'] - FirebaseLogout: typeof import('./components/firebase/Logout.vue')['default'] - GraphqlAuthorization: typeof import('./components/graphql/Authorization.vue')['default'] - GraphqlField: typeof import('./components/graphql/Field.vue')['default'] - GraphqlHeaders: typeof import('./components/graphql/Headers.vue')['default'] - GraphqlQuery: typeof import('./components/graphql/Query.vue')['default'] - GraphqlRequest: typeof import('./components/graphql/Request.vue')['default'] - GraphqlRequestOptions: typeof import('./components/graphql/RequestOptions.vue')['default'] - GraphqlRequestTab: typeof import('./components/graphql/RequestTab.vue')['default'] - GraphqlResponse: typeof import('./components/graphql/Response.vue')['default'] - GraphqlSidebar: typeof import('./components/graphql/Sidebar.vue')['default'] - GraphqlSubscriptionLog: typeof import('./components/graphql/SubscriptionLog.vue')['default'] - GraphqlTabHead: typeof import('./components/graphql/TabHead.vue')['default'] - GraphqlType: typeof import('./components/graphql/Type.vue')['default'] - GraphqlTypeLink: typeof import('./components/graphql/TypeLink.vue')['default'] - GraphqlVariable: typeof import('./components/graphql/Variable.vue')['default'] - History: typeof import('./components/history/index.vue')['default'] - HistoryGraphqlCard: typeof import('./components/history/graphql/Card.vue')['default'] - HistoryRestCard: typeof import('./components/history/rest/Card.vue')['default'] - HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'] - HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'] - HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'] - HoppSmartCheckbox: typeof import('@hoppscotch/ui')['HoppSmartCheckbox'] - HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'] - HoppSmartExpand: typeof import('@hoppscotch/ui')['HoppSmartExpand'] - HoppSmartFileChip: typeof import('@hoppscotch/ui')['HoppSmartFileChip'] - HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput'] - HoppSmartIntersection: typeof import('@hoppscotch/ui')['HoppSmartIntersection'] - 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'] - HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing'] - HoppSmartRadio: typeof import('@hoppscotch/ui')['HoppSmartRadio'] - HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup'] - HoppSmartSelectWrapper: typeof import('@hoppscotch/ui')['HoppSmartSelectWrapper'] - HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver'] - HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'] - HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab'] - HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs'] - HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle'] - HoppSmartTree: typeof import('@hoppscotch/ui')['HoppSmartTree'] - HoppSmartWindow: typeof import('@hoppscotch/ui')['HoppSmartWindow'] - HoppSmartWindows: typeof import('@hoppscotch/ui')['HoppSmartWindows'] - HttpAuthorization: typeof import('./components/http/Authorization.vue')['default'] - HttpAuthorizationApiKey: typeof import('./components/http/authorization/ApiKey.vue')['default'] - HttpAuthorizationBasic: typeof import('./components/http/authorization/Basic.vue')['default'] - HttpBody: typeof import('./components/http/Body.vue')['default'] - HttpBodyParameters: typeof import('./components/http/BodyParameters.vue')['default'] - HttpCodegenModal: typeof import('./components/http/CodegenModal.vue')['default'] - HttpHeaders: typeof import('./components/http/Headers.vue')['default'] - HttpImportCurl: typeof import('./components/http/ImportCurl.vue')['default'] - HttpOAuth2Authorization: typeof import('./components/http/OAuth2Authorization.vue')['default'] - HttpParameters: typeof import('./components/http/Parameters.vue')['default'] - HttpPreRequestScript: typeof import('./components/http/PreRequestScript.vue')['default'] - HttpRawBody: typeof import('./components/http/RawBody.vue')['default'] - HttpReqChangeConfirmModal: typeof import('./components/http/ReqChangeConfirmModal.vue')['default'] - HttpRequest: typeof import('./components/http/Request.vue')['default'] - HttpRequestOptions: typeof import('./components/http/RequestOptions.vue')['default'] - HttpRequestTab: typeof import('./components/http/RequestTab.vue')['default'] - HttpResponse: typeof import('./components/http/Response.vue')['default'] - HttpResponseMeta: typeof import('./components/http/ResponseMeta.vue')['default'] - HttpSidebar: typeof import('./components/http/Sidebar.vue')['default'] - HttpTabHead: typeof import('./components/http/TabHead.vue')['default'] - HttpTestResult: typeof import('./components/http/TestResult.vue')['default'] - HttpTestResultEntry: typeof import('./components/http/TestResultEntry.vue')['default'] - HttpTestResultEnv: typeof import('./components/http/TestResultEnv.vue')['default'] - HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default'] - HttpTests: typeof import('./components/http/Tests.vue')['default'] - HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default'] - IconLucideActivity: typeof import('~icons/lucide/activity')['default'] - IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default'] - IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default'] - IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default'] - IconLucideBrush: typeof import('~icons/lucide/brush')['default'] - IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default'] - IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default'] - IconLucideGlobe: typeof import('~icons/lucide/globe')['default'] - IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default'] - IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] - IconLucideInfo: typeof import('~icons/lucide/info')['default'] - IconLucideLayers: typeof import('~icons/lucide/layers')['default'] - IconLucideListEnd: typeof import('~icons/lucide/list-end')['default'] - IconLucideMinus: typeof import('~icons/lucide/minus')['default'] - IconLucideRss: typeof import('~icons/lucide/rss')['default'] - IconLucideSearch: typeof import('~icons/lucide/search')['default'] - IconLucideUsers: typeof import('~icons/lucide/users')['default'] - IconLucideX: typeof import('~icons/lucide/x')['default'] - ImportExportBase: typeof import('./components/importExport/Base.vue')['default'] - ImportExportImportExportList: typeof import('./components/importExport/ImportExportList.vue')['default'] - ImportExportImportExportSourcesList: typeof import('./components/importExport/ImportExportSourcesList.vue')['default'] - ImportExportImportExportStepsFileImport: typeof import('./components/importExport/ImportExportSteps/FileImport.vue')['default'] - ImportExportImportExportStepsMyCollectionImport: typeof import('./components/importExport/ImportExportSteps/MyCollectionImport.vue')['default'] - ImportExportImportExportStepsUrlImport: typeof import('./components/importExport/ImportExportSteps/UrlImport.vue')['default'] - InterceptorsErrorPlaceholder: typeof import('./components/interceptors/ErrorPlaceholder.vue')['default'] - InterceptorsExtensionSubtitle: typeof import('./components/interceptors/ExtensionSubtitle.vue')['default'] - LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default'] - LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default'] - LensesRenderersAudioLensRenderer: typeof import('./components/lenses/renderers/AudioLensRenderer.vue')['default'] - LensesRenderersHTMLLensRenderer: typeof import('./components/lenses/renderers/HTMLLensRenderer.vue')['default'] - LensesRenderersImageLensRenderer: typeof import('./components/lenses/renderers/ImageLensRenderer.vue')['default'] - LensesRenderersJSONLensRenderer: typeof import('./components/lenses/renderers/JSONLensRenderer.vue')['default'] - LensesRenderersPDFLensRenderer: typeof import('./components/lenses/renderers/PDFLensRenderer.vue')['default'] - LensesRenderersRawLensRenderer: typeof import('./components/lenses/renderers/RawLensRenderer.vue')['default'] - LensesRenderersVideoLensRenderer: typeof import('./components/lenses/renderers/VideoLensRenderer.vue')['default'] - LensesRenderersXMLLensRenderer: typeof import('./components/lenses/renderers/XMLLensRenderer.vue')['default'] - LensesResponseBodyRenderer: typeof import('./components/lenses/ResponseBodyRenderer.vue')['default'] - ProfileUserDelete: typeof import('./components/profile/UserDelete.vue')['default'] - RealtimeCommunication: typeof import('./components/realtime/Communication.vue')['default'] - RealtimeConnectionConfig: typeof import('./components/realtime/ConnectionConfig.vue')['default'] - RealtimeLog: typeof import('./components/realtime/Log.vue')['default'] - RealtimeLogEntry: typeof import('./components/realtime/LogEntry.vue')['default'] - RealtimeSubscription: typeof import('./components/realtime/Subscription.vue')['default'] - SettingsExtension: typeof import('./components/settings/Extension.vue')['default'] - SettingsProxy: typeof import('./components/settings/Proxy.vue')['default'] - Share: typeof import('./components/share/index.vue')['default'] - ShareCreateModal: typeof import('./components/share/CreateModal.vue')['default'] - ShareCustomizeModal: typeof import('./components/share/CustomizeModal.vue')['default'] - ShareModal: typeof import('./components/share/Modal.vue')['default'] - ShareRequest: typeof import('./components/share/Request.vue')['default'] - ShareTemplatesButton: typeof import('./components/share/templates/Button.vue')['default'] - ShareTemplatesEmbeds: typeof import('./components/share/templates/Embeds.vue')['default'] - ShareTemplatesLink: typeof import('./components/share/templates/Link.vue')['default'] - SmartAccentModePicker: typeof import('./components/smart/AccentModePicker.vue')['default'] - SmartChangeLanguage: typeof import('./components/smart/ChangeLanguage.vue')['default'] - SmartColorModePicker: typeof import('./components/smart/ColorModePicker.vue')['default'] - SmartEnvInput: typeof import('./components/smart/EnvInput.vue')['default'] - TabPrimary: typeof import('./components/tab/Primary.vue')['default'] - TabSecondary: typeof import('./components/tab/Secondary.vue')['default'] - Teams: typeof import('./components/teams/index.vue')['default'] - TeamsAdd: typeof import('./components/teams/Add.vue')['default'] - TeamsEdit: typeof import('./components/teams/Edit.vue')['default'] - TeamsInvite: typeof import('./components/teams/Invite.vue')['default'] - TeamsMemberStack: typeof import('./components/teams/MemberStack.vue')['default'] - TeamsModal: typeof import('./components/teams/Modal.vue')['default'] - TeamsTeam: typeof import('./components/teams/Team.vue')['default'] - Tippy: typeof import('vue-tippy')['Tippy'] - WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default'] - WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default'] + AppActionHandler: (typeof import("./components/app/ActionHandler.vue"))["default"] + AppBanner: (typeof import("./components/app/Banner.vue"))["default"] + AppContextMenu: (typeof import("./components/app/ContextMenu.vue"))["default"] + AppDeveloperOptions: (typeof import("./components/app/DeveloperOptions.vue"))["default"] + AppFooter: (typeof import("./components/app/Footer.vue"))["default"] + AppGitHubStarButton: (typeof import("./components/app/GitHubStarButton.vue"))["default"] + AppHeader: (typeof import("./components/app/Header.vue"))["default"] + AppInspection: (typeof import("./components/app/Inspection.vue"))["default"] + AppInterceptor: (typeof import("./components/app/Interceptor.vue"))["default"] + AppLogo: (typeof import("./components/app/Logo.vue"))["default"] + AppOptions: (typeof import("./components/app/Options.vue"))["default"] + AppPaneLayout: (typeof import("./components/app/PaneLayout.vue"))["default"] + AppShare: (typeof import("./components/app/Share.vue"))["default"] + AppShortcuts: (typeof import("./components/app/Shortcuts.vue"))["default"] + AppShortcutsEntry: (typeof import("./components/app/ShortcutsEntry.vue"))["default"] + AppShortcutsPrompt: (typeof import("./components/app/ShortcutsPrompt.vue"))["default"] + AppSidenav: (typeof import("./components/app/Sidenav.vue"))["default"] + AppSpotlight: (typeof import("./components/app/spotlight/index.vue"))["default"] + AppSpotlightEntry: (typeof import("./components/app/spotlight/Entry.vue"))["default"] + AppSpotlightEntryGQLHistory: (typeof import("./components/app/spotlight/entry/GQLHistory.vue"))["default"] + AppSpotlightEntryGQLRequest: (typeof import("./components/app/spotlight/entry/GQLRequest.vue"))["default"] + AppSpotlightEntryIconSelected: (typeof import("./components/app/spotlight/entry/IconSelected.vue"))["default"] + AppSpotlightEntryRESTHistory: (typeof import("./components/app/spotlight/entry/RESTHistory.vue"))["default"] + AppSpotlightEntryRESTRequest: (typeof import("./components/app/spotlight/entry/RESTRequest.vue"))["default"] + AppSupport: (typeof import("./components/app/Support.vue"))["default"] + Collections: (typeof import("./components/collections/index.vue"))["default"] + CollectionsAdd: (typeof import("./components/collections/Add.vue"))["default"] + CollectionsAddFolder: (typeof import("./components/collections/AddFolder.vue"))["default"] + CollectionsAddRequest: (typeof import("./components/collections/AddRequest.vue"))["default"] + CollectionsCollection: (typeof import("./components/collections/Collection.vue"))["default"] + CollectionsEdit: (typeof import("./components/collections/Edit.vue"))["default"] + CollectionsEditFolder: (typeof import("./components/collections/EditFolder.vue"))["default"] + CollectionsEditRequest: (typeof import("./components/collections/EditRequest.vue"))["default"] + CollectionsGraphql: (typeof import("./components/collections/graphql/index.vue"))["default"] + CollectionsGraphqlAdd: (typeof import("./components/collections/graphql/Add.vue"))["default"] + CollectionsGraphqlAddFolder: (typeof import("./components/collections/graphql/AddFolder.vue"))["default"] + CollectionsGraphqlAddRequest: (typeof import("./components/collections/graphql/AddRequest.vue"))["default"] + CollectionsGraphqlCollection: (typeof import("./components/collections/graphql/Collection.vue"))["default"] + CollectionsGraphqlEdit: (typeof import("./components/collections/graphql/Edit.vue"))["default"] + CollectionsGraphqlEditFolder: (typeof import("./components/collections/graphql/EditFolder.vue"))["default"] + CollectionsGraphqlEditRequest: (typeof import("./components/collections/graphql/EditRequest.vue"))["default"] + CollectionsGraphqlFolder: (typeof import("./components/collections/graphql/Folder.vue"))["default"] + CollectionsGraphqlImportExport: (typeof import("./components/collections/graphql/ImportExport.vue"))["default"] + CollectionsGraphqlRequest: (typeof import("./components/collections/graphql/Request.vue"))["default"] + CollectionsImportExport: (typeof import("./components/collections/ImportExport.vue"))["default"] + CollectionsMyCollections: (typeof import("./components/collections/MyCollections.vue"))["default"] + CollectionsProperties: (typeof import("./components/collections/Properties.vue"))["default"] + CollectionsRequest: (typeof import("./components/collections/Request.vue"))["default"] + CollectionsSaveRequest: (typeof import("./components/collections/SaveRequest.vue"))["default"] + CollectionsTeamCollections: (typeof import("./components/collections/TeamCollections.vue"))["default"] + CookiesAllModal: (typeof import("./components/cookies/AllModal.vue"))["default"] + CookiesEditCookie: (typeof import("./components/cookies/EditCookie.vue"))["default"] + Embeds: (typeof import("./components/embeds/index.vue"))["default"] + Environments: (typeof import("./components/environments/index.vue"))["default"] + EnvironmentsAdd: (typeof import("./components/environments/Add.vue"))["default"] + EnvironmentsImportExport: (typeof import("./components/environments/ImportExport.vue"))["default"] + EnvironmentsMy: (typeof import("./components/environments/my/index.vue"))["default"] + EnvironmentsMyDetails: (typeof import("./components/environments/my/Details.vue"))["default"] + EnvironmentsMyEnvironment: (typeof import("./components/environments/my/Environment.vue"))["default"] + EnvironmentsSelector: (typeof import("./components/environments/Selector.vue"))["default"] + EnvironmentsTeams: (typeof import("./components/environments/teams/index.vue"))["default"] + EnvironmentsTeamsDetails: (typeof import("./components/environments/teams/Details.vue"))["default"] + EnvironmentsTeamsEnvironment: (typeof import("./components/environments/teams/Environment.vue"))["default"] + FirebaseLogin: (typeof import("./components/firebase/Login.vue"))["default"] + FirebaseLogout: (typeof import("./components/firebase/Logout.vue"))["default"] + GraphqlAuthorization: (typeof import("./components/graphql/Authorization.vue"))["default"] + GraphqlField: (typeof import("./components/graphql/Field.vue"))["default"] + GraphqlHeaders: (typeof import("./components/graphql/Headers.vue"))["default"] + GraphqlQuery: (typeof import("./components/graphql/Query.vue"))["default"] + GraphqlRequest: (typeof import("./components/graphql/Request.vue"))["default"] + GraphqlRequestOptions: (typeof import("./components/graphql/RequestOptions.vue"))["default"] + GraphqlRequestTab: (typeof import("./components/graphql/RequestTab.vue"))["default"] + GraphqlResponse: (typeof import("./components/graphql/Response.vue"))["default"] + GraphqlSidebar: (typeof import("./components/graphql/Sidebar.vue"))["default"] + GraphqlSubscriptionLog: (typeof import("./components/graphql/SubscriptionLog.vue"))["default"] + GraphqlTabHead: (typeof import("./components/graphql/TabHead.vue"))["default"] + GraphqlType: (typeof import("./components/graphql/Type.vue"))["default"] + GraphqlTypeLink: (typeof import("./components/graphql/TypeLink.vue"))["default"] + GraphqlVariable: (typeof import("./components/graphql/Variable.vue"))["default"] + History: (typeof import("./components/history/index.vue"))["default"] + HistoryGraphqlCard: (typeof import("./components/history/graphql/Card.vue"))["default"] + HistoryRestCard: (typeof import("./components/history/rest/Card.vue"))["default"] + HoppButtonPrimary: (typeof import("@hoppscotch/ui"))["HoppButtonPrimary"] + HoppButtonSecondary: (typeof import("@hoppscotch/ui"))["HoppButtonSecondary"] + HoppSmartAnchor: (typeof import("@hoppscotch/ui"))["HoppSmartAnchor"] + HoppSmartCheckbox: (typeof import("@hoppscotch/ui"))["HoppSmartCheckbox"] + HoppSmartConfirmModal: (typeof import("@hoppscotch/ui"))["HoppSmartConfirmModal"] + HoppSmartExpand: (typeof import("@hoppscotch/ui"))["HoppSmartExpand"] + HoppSmartFileChip: (typeof import("@hoppscotch/ui"))["HoppSmartFileChip"] + HoppSmartInput: (typeof import("@hoppscotch/ui"))["HoppSmartInput"] + HoppSmartIntersection: (typeof import("@hoppscotch/ui"))["HoppSmartIntersection"] + 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"] + HoppSmartProgressRing: (typeof import("@hoppscotch/ui"))["HoppSmartProgressRing"] + HoppSmartRadio: (typeof import("@hoppscotch/ui"))["HoppSmartRadio"] + HoppSmartRadioGroup: (typeof import("@hoppscotch/ui"))["HoppSmartRadioGroup"] + HoppSmartSelectWrapper: (typeof import("@hoppscotch/ui"))["HoppSmartSelectWrapper"] + HoppSmartSlideOver: (typeof import("@hoppscotch/ui"))["HoppSmartSlideOver"] + HoppSmartSpinner: (typeof import("@hoppscotch/ui"))["HoppSmartSpinner"] + HoppSmartTab: (typeof import("@hoppscotch/ui"))["HoppSmartTab"] + HoppSmartTabs: (typeof import("@hoppscotch/ui"))["HoppSmartTabs"] + HoppSmartToggle: (typeof import("@hoppscotch/ui"))["HoppSmartToggle"] + HoppSmartTree: (typeof import("@hoppscotch/ui"))["HoppSmartTree"] + HoppSmartWindow: (typeof import("@hoppscotch/ui"))["HoppSmartWindow"] + HoppSmartWindows: (typeof import("@hoppscotch/ui"))["HoppSmartWindows"] + HttpAuthorization: (typeof import("./components/http/Authorization.vue"))["default"] + HttpAuthorizationApiKey: (typeof import("./components/http/authorization/ApiKey.vue"))["default"] + HttpAuthorizationBasic: (typeof import("./components/http/authorization/Basic.vue"))["default"] + HttpBody: (typeof import("./components/http/Body.vue"))["default"] + HttpBodyParameters: (typeof import("./components/http/BodyParameters.vue"))["default"] + HttpCodegenModal: (typeof import("./components/http/CodegenModal.vue"))["default"] + HttpHeaders: (typeof import("./components/http/Headers.vue"))["default"] + HttpImportCurl: (typeof import("./components/http/ImportCurl.vue"))["default"] + HttpOAuth2Authorization: (typeof import("./components/http/OAuth2Authorization.vue"))["default"] + HttpParameters: (typeof import("./components/http/Parameters.vue"))["default"] + HttpPreRequestScript: (typeof import("./components/http/PreRequestScript.vue"))["default"] + HttpRawBody: (typeof import("./components/http/RawBody.vue"))["default"] + HttpReqChangeConfirmModal: (typeof import("./components/http/ReqChangeConfirmModal.vue"))["default"] + HttpRequest: (typeof import("./components/http/Request.vue"))["default"] + HttpRequestOptions: (typeof import("./components/http/RequestOptions.vue"))["default"] + HttpRequestTab: (typeof import("./components/http/RequestTab.vue"))["default"] + HttpResponse: (typeof import("./components/http/Response.vue"))["default"] + HttpResponseMeta: (typeof import("./components/http/ResponseMeta.vue"))["default"] + HttpSidebar: (typeof import("./components/http/Sidebar.vue"))["default"] + HttpTabHead: (typeof import("./components/http/TabHead.vue"))["default"] + HttpTestResult: (typeof import("./components/http/TestResult.vue"))["default"] + HttpTestResultEntry: (typeof import("./components/http/TestResultEntry.vue"))["default"] + HttpTestResultEnv: (typeof import("./components/http/TestResultEnv.vue"))["default"] + HttpTestResultReport: (typeof import("./components/http/TestResultReport.vue"))["default"] + HttpTests: (typeof import("./components/http/Tests.vue"))["default"] + HttpURLEncodedParams: (typeof import("./components/http/URLEncodedParams.vue"))["default"] + IconLucideActivity: (typeof import("~icons/lucide/activity"))["default"] + IconLucideAlertTriangle: (typeof import("~icons/lucide/alert-triangle"))["default"] + IconLucideArrowLeft: (typeof import("~icons/lucide/arrow-left"))["default"] + IconLucideArrowUpRight: (typeof import("~icons/lucide/arrow-up-right"))["default"] + IconLucideBrush: (typeof import("~icons/lucide/brush"))["default"] + IconLucideCheckCircle: (typeof import("~icons/lucide/check-circle"))["default"] + IconLucideChevronRight: (typeof import("~icons/lucide/chevron-right"))["default"] + IconLucideGlobe: (typeof import("~icons/lucide/globe"))["default"] + IconLucideHelpCircle: (typeof import("~icons/lucide/help-circle"))["default"] + IconLucideInbox: (typeof import("~icons/lucide/inbox"))["default"] + IconLucideInfo: (typeof import("~icons/lucide/info"))["default"] + IconLucideLayers: (typeof import("~icons/lucide/layers"))["default"] + IconLucideListEnd: (typeof import("~icons/lucide/list-end"))["default"] + IconLucideMinus: (typeof import("~icons/lucide/minus"))["default"] + IconLucideRss: (typeof import("~icons/lucide/rss"))["default"] + IconLucideSearch: (typeof import("~icons/lucide/search"))["default"] + IconLucideUsers: (typeof import("~icons/lucide/users"))["default"] + IconLucideX: (typeof import("~icons/lucide/x"))["default"] + ImportExportBase: (typeof import("./components/importExport/Base.vue"))["default"] + ImportExportImportExportList: (typeof import("./components/importExport/ImportExportList.vue"))["default"] + ImportExportImportExportSourcesList: (typeof import("./components/importExport/ImportExportSourcesList.vue"))["default"] + ImportExportImportExportStepsFileImport: (typeof import("./components/importExport/ImportExportSteps/FileImport.vue"))["default"] + ImportExportImportExportStepsMyCollectionImport: (typeof import("./components/importExport/ImportExportSteps/MyCollectionImport.vue"))["default"] + ImportExportImportExportStepsUrlImport: (typeof import("./components/importExport/ImportExportSteps/UrlImport.vue"))["default"] + InterceptorsErrorPlaceholder: (typeof import("./components/interceptors/ErrorPlaceholder.vue"))["default"] + InterceptorsExtensionSubtitle: (typeof import("./components/interceptors/ExtensionSubtitle.vue"))["default"] + LensesHeadersRenderer: (typeof import("./components/lenses/HeadersRenderer.vue"))["default"] + LensesHeadersRendererEntry: (typeof import("./components/lenses/HeadersRendererEntry.vue"))["default"] + LensesRenderersAudioLensRenderer: (typeof import("./components/lenses/renderers/AudioLensRenderer.vue"))["default"] + LensesRenderersHTMLLensRenderer: (typeof import("./components/lenses/renderers/HTMLLensRenderer.vue"))["default"] + LensesRenderersImageLensRenderer: (typeof import("./components/lenses/renderers/ImageLensRenderer.vue"))["default"] + LensesRenderersJSONLensRenderer: (typeof import("./components/lenses/renderers/JSONLensRenderer.vue"))["default"] + LensesRenderersPDFLensRenderer: (typeof import("./components/lenses/renderers/PDFLensRenderer.vue"))["default"] + LensesRenderersRawLensRenderer: (typeof import("./components/lenses/renderers/RawLensRenderer.vue"))["default"] + LensesRenderersVideoLensRenderer: (typeof import("./components/lenses/renderers/VideoLensRenderer.vue"))["default"] + LensesRenderersXMLLensRenderer: (typeof import("./components/lenses/renderers/XMLLensRenderer.vue"))["default"] + LensesResponseBodyRenderer: (typeof import("./components/lenses/ResponseBodyRenderer.vue"))["default"] + ProfileUserDelete: (typeof import("./components/profile/UserDelete.vue"))["default"] + RealtimeCommunication: (typeof import("./components/realtime/Communication.vue"))["default"] + RealtimeConnectionConfig: (typeof import("./components/realtime/ConnectionConfig.vue"))["default"] + RealtimeLog: (typeof import("./components/realtime/Log.vue"))["default"] + RealtimeLogEntry: (typeof import("./components/realtime/LogEntry.vue"))["default"] + RealtimeSubscription: (typeof import("./components/realtime/Subscription.vue"))["default"] + SettingsExtension: (typeof import("./components/settings/Extension.vue"))["default"] + SettingsProxy: (typeof import("./components/settings/Proxy.vue"))["default"] + Share: (typeof import("./components/share/index.vue"))["default"] + ShareCreateModal: (typeof import("./components/share/CreateModal.vue"))["default"] + ShareCustomizeModal: (typeof import("./components/share/CustomizeModal.vue"))["default"] + ShareModal: (typeof import("./components/share/Modal.vue"))["default"] + ShareRequest: (typeof import("./components/share/Request.vue"))["default"] + ShareTemplatesButton: (typeof import("./components/share/templates/Button.vue"))["default"] + ShareTemplatesEmbeds: (typeof import("./components/share/templates/Embeds.vue"))["default"] + ShareTemplatesLink: (typeof import("./components/share/templates/Link.vue"))["default"] + SmartAccentModePicker: (typeof import("./components/smart/AccentModePicker.vue"))["default"] + SmartChangeLanguage: (typeof import("./components/smart/ChangeLanguage.vue"))["default"] + SmartColorModePicker: (typeof import("./components/smart/ColorModePicker.vue"))["default"] + SmartEnvInput: (typeof import("./components/smart/EnvInput.vue"))["default"] + TabPrimary: (typeof import("./components/tab/Primary.vue"))["default"] + TabSecondary: (typeof import("./components/tab/Secondary.vue"))["default"] + Teams: (typeof import("./components/teams/index.vue"))["default"] + TeamsAdd: (typeof import("./components/teams/Add.vue"))["default"] + TeamsEdit: (typeof import("./components/teams/Edit.vue"))["default"] + TeamsInvite: (typeof import("./components/teams/Invite.vue"))["default"] + TeamsMemberStack: (typeof import("./components/teams/MemberStack.vue"))["default"] + TeamsModal: (typeof import("./components/teams/Modal.vue"))["default"] + TeamsTeam: (typeof import("./components/teams/Team.vue"))["default"] + Tippy: (typeof import("vue-tippy"))["Tippy"] + WorkspaceCurrent: (typeof import("./components/workspace/Current.vue"))["default"] + WorkspaceSelector: (typeof import("./components/workspace/Selector.vue"))["default"] } } From fa51759b83790f09ee906aac84d5ebafe9d46210 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Fri, 8 Mar 2024 10:05:31 +0530 Subject: [PATCH 50/60] chore: updated hopp ui version --- packages/hoppscotch-sh-admin/package.json | 2 +- .../src/pages/users/index.vue | 2 +- pnpm-lock.yaml | 33 +++++++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/packages/hoppscotch-sh-admin/package.json b/packages/hoppscotch-sh-admin/package.json index 16a28aa362..94839ff15b 100644 --- a/packages/hoppscotch-sh-admin/package.json +++ b/packages/hoppscotch-sh-admin/package.json @@ -17,7 +17,7 @@ "@fontsource-variable/material-symbols-rounded": "5.0.5", "@fontsource-variable/roboto-mono": "5.0.6", "@graphql-typed-document-node/core": "3.1.1", - "@hoppscotch/ui": "0.1.0", + "@hoppscotch/ui": "0.1.2", "@hoppscotch/vue-toasted": "0.1.0", "@intlify/unplugin-vue-i18n": "1.2.0", "@types/cors": "2.8.13", diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 6f7296f8f1..4c19cbfd30 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -262,7 +262,7 @@ const headings = [ ]; // Get Paginated Results of all the users in the infra -const usersPerPage = 2; +const usersPerPage = 20; const { fetching, error, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28ad9194d3..f19aa123a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1258,8 +1258,8 @@ importers: specifier: 3.1.1 version: 3.1.1(graphql@16.6.0) '@hoppscotch/ui': - specifier: 0.1.0 - version: 0.1.0(eslint@8.55.0)(terser@5.27.0)(vite@3.2.4)(vue@3.3.9) + specifier: 0.1.2 + version: 0.1.2(eslint@8.55.0)(terser@5.27.0)(vite@3.2.4)(vue@3.3.9) '@hoppscotch/vue-toasted': specifier: 0.1.0 version: 0.1.0(vue@3.3.9) @@ -6015,13 +6015,14 @@ packages: lodash-es: 4.17.21 path: 0.12.7 vite-plugin-eslint: 1.8.1(eslint@8.55.0)(vite@3.2.4) - vue: 3.3.9(typescript@4.9.3) + vue: 3.3.9(typescript@4.9.5) vuedraggable-es: 4.1.1(vue@3.3.9) transitivePeerDependencies: - '@vue/composition-api' - eslint - terser - vite + dev: true /@hoppscotch/ui@0.1.0(eslint@8.55.0)(terser@5.27.0)(vite@4.5.0)(vue@3.3.9): resolution: {integrity: sha512-+4iHdfO7gRn7l3vpnPcQZbgdA+uE/K1KQX0/eUFcCWvja/C3eSM0db31MRX2cz1KYGwiezzhhVe21mIT4a0CZQ==} @@ -6049,6 +6050,32 @@ packages: - vite dev: false + /@hoppscotch/ui@0.1.2(eslint@8.55.0)(terser@5.27.0)(vite@3.2.4)(vue@3.3.9): + resolution: {integrity: sha512-bBn7Km1iIFMBsXgnrDLqTBzz29XOPRZcRbQd18DZMYxoR7WQo9amBfa850vk5debYQx2+Mb0ExOnrGVO1QlBRg==} + engines: {node: '>=16'} + peerDependencies: + vue: 3.3.9 + dependencies: + '@boringer-avatars/vue3': 0.2.1(vue@3.3.9) + '@fontsource-variable/inter': 5.0.15 + '@fontsource-variable/material-symbols-rounded': 5.0.16 + '@fontsource-variable/roboto-mono': 5.0.16 + '@hoppscotch/vue-toasted': 0.1.0(vue@3.3.9) + '@vitejs/plugin-legacy': 2.3.0(terser@5.27.0)(vite@3.2.4) + '@vueuse/core': 8.7.5(vue@3.3.9) + fp-ts: 2.16.2 + lodash-es: 4.17.21 + path: 0.12.7 + vite-plugin-eslint: 1.8.1(eslint@8.55.0)(vite@3.2.4) + vue: 3.3.9(typescript@4.9.3) + vuedraggable-es: 4.1.1(vue@3.3.9) + transitivePeerDependencies: + - '@vue/composition-api' + - eslint + - terser + - vite + dev: false + /@hoppscotch/vue-toasted@0.1.0(vue@3.3.9): resolution: {integrity: sha512-DIgmeTHxWwX5UeaHLEqDYNLJFGRosx/5N1fCHkaO8zt+sZv8GrHlkrIpjfKF2drmA3kKw5cY42Cw7WuCoabR3g==} peerDependencies: From 1e2469f7f9596ccf45b24631901ffba85f9b31be Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Sat, 9 Mar 2024 11:03:39 +0530 Subject: [PATCH 51/60] fix: pagination and search not computing properly --- .../src/pages/users/index.vue | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 4c19cbfd30..63507ee882 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -26,7 +26,7 @@ { searchQuery.value = input; - await refetch({ searchString: input, take: usersPerPage, skip: 0 }); + if (input.length === 0) { + await refetch({ + searchString: '', + take: usersPerPage, + skip: (pageNumber.value - 1) * usersPerPage, + }); + } else { + // If search query is present, fetch all the users filtered by the search query + await refetch({ searchString: input, take: usersCount.value!, skip: 0 }); + } }; +// Final Users List after Search and Pagination operations +const finalUsersList = computed(() => + // If search query is present, filter the list based on the search query and return the paginated results + // Else just return the paginated results directly + searchQuery.value.length > 0 + ? usersList.value.slice( + (pageNumber.value - 1) * usersPerPage, + pageNumber.value * usersPerPage + ) + : usersList.value +); + watch(searchQuery, () => { debounce(() => { handleSearch(searchQuery.value); @@ -312,23 +333,29 @@ watch(fetching, (fetching) => { }); // Pagination +const pageNumber = ref(1); const { data } = useQuery({ query: MetricsDocument }); const usersCount = computed(() => data?.value?.infra.usersCount); const totalPages = computed(() => { if (!usersCount.value) return 0; if (searchQuery.value.length > 0) { - return usersList.value.length; + return Math.ceil(usersList.value.length / usersPerPage); } return Math.ceil(usersCount.value / usersPerPage); }); const handlePageChange = async (page: number) => { + pageNumber.value = page; if (page < 1 || page > totalPages.value) { return; + } else if (searchQuery.value.length > 0) { + // Simulate fetching state + fetching.value = true; + debounce(() => (fetching.value = false), 500); } else { await refetch({ - searchString: searchQuery.value, + searchString: '', take: usersPerPage, skip: (page - 1) * usersPerPage, }); From 80793fa93ca311a857ec159e1b4298e8547dc795 Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Sat, 9 Mar 2024 20:52:08 +0530 Subject: [PATCH 52/60] refactor: implemented onsite pagination instead of using smart table pagination --- .../hoppscotch-sh-admin/src/components.d.ts | 101 +++++++++--------- .../src/pages/users/index.vue | 81 ++++++++++---- 2 files changed, 114 insertions(+), 68 deletions(-) diff --git a/packages/hoppscotch-sh-admin/src/components.d.ts b/packages/hoppscotch-sh-admin/src/components.d.ts index 76edcdbada..f6d1e02c41 100644 --- a/packages/hoppscotch-sh-admin/src/components.d.ts +++ b/packages/hoppscotch-sh-admin/src/components.d.ts @@ -1,59 +1,60 @@ // 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']; - HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']; - 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']; - HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable']; - HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']; - HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']; - IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']; - IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']; - IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default']; - IconLucideInbox: typeof import('~icons/lucide/inbox')['default']; - IconLucideSearch: typeof import('~icons/lucide/search')['default']; - IconLucideUser: typeof import('~icons/lucide/user')['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']; - UsersTable: typeof import('./components/users/Table.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'] + HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete'] + 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'] + HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable'] + HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs'] + HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle'] + IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default'] + IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'] + IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default'] + IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] + IconLucideSearch: typeof import('~icons/lucide/search')['default'] + IconLucideUser: typeof import('~icons/lucide/user')['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'] + UsersTable: typeof import('./components/users/Table.vue')['default'] } + } diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue index 63507ee882..2d75c06f3f 100644 --- a/packages/hoppscotch-sh-admin/src/pages/users/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -23,14 +23,33 @@
{{ t('users.load_list_error') }}
+
+ + +
+ {{ page }} +
+ + +
+