Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(sh-admin): enhanced user management in admin dashboard #3814

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
8809c3b
feat: new mutations for bulk delete, and enabling and disabling of th…
JoelJacobStephen Feb 5, 2024
23ceb11
refactor: implemented bulk actions in users page
JoelJacobStephen Feb 5, 2024
0083cb7
refactor: updated index component to support selected rows as a useVm…
JoelJacobStephen Feb 5, 2024
50f4888
feat: new users list mutation
JoelJacobStephen Feb 5, 2024
fdeb4b1
refactor: updated index to support new search operation in users table
JoelJacobStephen Feb 5, 2024
9702b2e
feat: new pagination system implemented in users table
JoelJacobStephen Feb 6, 2024
f66c78f
feat: ability to revoke user invitations
JoelJacobStephen Feb 6, 2024
7021feb
style: ui fixes in users page
JoelJacobStephen Feb 6, 2024
94d77a1
chore: updated debounce value for users table
JoelJacobStephen Feb 8, 2024
f107c18
feat: new error messages in dashboard
JoelJacobStephen Feb 8, 2024
799c80a
refactor: new i18n strings for different new aspects in users module
JoelJacobStephen Feb 8, 2024
f66235e
feat: introduced ability to rename a user
JoelJacobStephen Feb 8, 2024
c1d3e06
refactor: updated i18n strings
JoelJacobStephen Feb 8, 2024
0818eb1
chore: cleaned up code in details component
JoelJacobStephen Feb 9, 2024
a91a384
fix: shared requests now adheres to new changes in usePagedQuery
JoelJacobStephen Feb 9, 2024
0cffedb
chore: cleaned up index component
JoelJacobStephen Feb 9, 2024
bd1021e
refactor: updated shared requests to adhere to the new table
JoelJacobStephen Feb 9, 2024
cdb3ecc
refactor: updated teams table to adhere to the new table
JoelJacobStephen Feb 9, 2024
84cd92a
chore: updated i18n strings for invited components
JoelJacobStephen Feb 9, 2024
8510e64
refactor: updated mutations to adhere to the new format introduced in…
JoelJacobStephen Feb 13, 2024
fbe8310
refactor: updated invited component to adhere to the new backend changes
JoelJacobStephen Feb 13, 2024
5d496a6
refactor: updated make users to admin and remove admin status to use …
JoelJacobStephen Feb 13, 2024
f751067
refactor: removed decprecated mutations
JoelJacobStephen Feb 13, 2024
5bb5fbf
refactor: updated deletion of users operation to use only one mutation
JoelJacobStephen Feb 13, 2024
2b4d08d
style: removed padding for shared request error message
JoelJacobStephen Feb 13, 2024
c118393
refactor: deletion of a single user now uses the new mutation
JoelJacobStephen Feb 13, 2024
1e3272f
refactor: updated styles and i18n strings in invited components
JoelJacobStephen Feb 13, 2024
e24b961
refactor: updated individual user components to adhere to the new bac…
JoelJacobStephen Feb 13, 2024
42a2e37
feat: added spinner functionality to the users table
JoelJacobStephen Feb 14, 2024
156baa1
feat: bulk actions are now possible with pending invites
JoelJacobStephen Feb 14, 2024
90309c0
refactor: fixed infinite spinner issue
JoelJacobStephen Feb 14, 2024
46f9c6e
fix: spinner issue in table
JoelJacobStephen Feb 14, 2024
b26f67f
refactor: code improvements and new i18n strings for invited component
JoelJacobStephen Feb 15, 2024
ff512f1
chore: code improvements to invite modal
JoelJacobStephen Feb 15, 2024
1d597be
refactor: improvements to index component and updated i18n strings
JoelJacobStephen Feb 15, 2024
81fdedd
refactor: updated error check with new error types
JoelJacobStephen Feb 15, 2024
172a6fe
fix: the header showing up on reload when list is empty
JoelJacobStephen Feb 15, 2024
a110ded
refactor: better responsiveness for invited page
JoelJacobStephen Feb 26, 2024
7ed8256
refactor: updated table component layout and removed unused searchbar…
JoelJacobStephen Feb 29, 2024
29cc15b
refactor: updated users table to adhere to removal of search and debo…
JoelJacobStephen Feb 29, 2024
3530883
refactor: updated table and users page to adhere to the new changes
JoelJacobStephen Mar 1, 2024
097d8c6
refactor: updated users and teams table to adhere to new loading and …
JoelJacobStephen Mar 1, 2024
7f44862
refactor: added a placeholder and empty-state in users table
JoelJacobStephen Mar 5, 2024
bd1be20
refactor: removed unnecessary props to invited table
JoelJacobStephen Mar 5, 2024
fa605d8
chore: updated @hoppscotch/ui version to 0.1.2
JoelJacobStephen Mar 7, 2024
88bb01c
refactor: removed Users Table
JoelJacobStephen Mar 7, 2024
acd9739
refactor: improvements to paged query
JoelJacobStephen Mar 7, 2024
9f0d1a2
refactor: replaced users table with HoppSmartTable
JoelJacobStephen Mar 7, 2024
cfd57e5
chore: component fixes
JoelJacobStephen Mar 8, 2024
fa51759
chore: updated hopp ui version
JoelJacobStephen Mar 8, 2024
1e2469f
fix: pagination and search not computing properly
JoelJacobStephen Mar 9, 2024
80793fa
refactor: implemented onsite pagination instead of using smart table …
JoelJacobStephen Mar 9, 2024
36460f3
fix: refetching even even search query is present
JoelJacobStephen Mar 9, 2024
4e88945
fix: computation is now based on input query
JoelJacobStephen Mar 9, 2024
80902d4
chore: code improvements in users page
JoelJacobStephen Mar 9, 2024
5c7458e
chore: add suggestions from review
jamesgeorge007 Mar 11, 2024
5123ce6
fix: multiple users selection computation
jamesgeorge007 Mar 12, 2024
099efd5
refactor: prevent mutating function args
jamesgeorge007 Mar 12, 2024
a83ec4c
refactor: rename slot prop as per context
jamesgeorge007 Mar 12, 2024
6b43960
refactor: new clear selection button to clear all selections
JoelJacobStephen Mar 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
416 changes: 208 additions & 208 deletions packages/hoppscotch-common/src/components.d.ts

Large diffs are not rendered by default.

48 changes: 41 additions & 7 deletions packages/hoppscotch-sh-admin/locales/en.json
Expand Up @@ -106,8 +106,18 @@
"admin_failure": "Failed to make user an admin!!",
"admin_success": "User is now an admin!!",
"and": "and",
"clear_selection": "Clear Selection",
"configure_auth": "Check out the documentation to configure auth providers.",
"confirm_admin_to_user": "Do you want to remove admin status from this user?",
"confirm_admins_to_users": "Do you want to remove admin status from selected users?",
"confirm_delete_invite": "Do you want to revoke the selected invite?",
"confirm_delete_invites": "Do you want to revoke selected invites?",
"confirm_user_deletion": "Confirm user deletion?",
"confirm_users_deletion": "Do you want to delete selected users?",
"confirm_user_to_admin": "Do you want to make this user into an admin?",
"confirm_users_to_admin": "Do you want to make selected users into admins?",
"confirm_logout": "Confirm Logout",
"created_on": "Created On",
"continue_email": "Continue with Email",
"continue_github": "Continue with Github",
"continue_google": "Continue with Google",
Expand All @@ -116,12 +126,21 @@
"create_team_failure": "Failed to create workspace!!",
"create_team_success": "Workspace created successfully!!",
"data_sharing_failure": "Failed to update data sharing settings",
"delete_invite_failure": "Failed to delete invite!!",
"delete_invites_failure": "Failed to delete selected invites!!",
"delete_invite_success": "Invite deleted successfully!!",
"delete_invites_success": "Selected invites deleted successfully!!",
"delete_request_failure": "Shared Request deletion failed!!",
"delete_request_success": "Shared Request deleted successfully!!",
"delete_team_failure": "Workspace deletion failed!!",
"delete_team_success": "Workspace deleted successfully!!",
"delete_some_users_failure": "Number of Users Not Deleted: {count}",
"delete_some_users_success": "Number of Users Deleted: {count}",
"delete_user_failed_only_one_admin": "Failed to delete user. There should be atleast one admin!!",
"delete_user_failure": "User deletion failed!!",
"delete_users_failure": "Failed to delete selected users!!",
"delete_user_success": "User deleted successfully!!",
"delete_users_success": "Selected users deleted successfully!!",
"email": "Email",
"email_failure": "Failed to send invitation",
"email_signin_failure": "Failed to login with Email",
Expand All @@ -146,16 +165,22 @@
"reenter_email": "Re-enter email",
"remove_admin_failure": "Failed to remove admin status!!",
"remove_admin_success": "Admin status removed!!",
"remove_admin_from_users_failure": "Failed to remove admin status from selected users!!",
"remove_admin_from_users_success": "Admin status removed from selected users!!",
"remove_admin_to_delete_user": "Remove admin privilege to delete the user!!",
"remove_admin_for_deletion": "Remove admin status before attempting deletion!!",
"remove_invitee_failure": "Removal of invitee failed!!",
"remove_invitee_success": "Removal of invitee is successfull!!",
"remove_member_failure": "Member couldn't be removed!!",
"remove_member_success": "Member removed successfully!!",
"rename_team_failure": "Failed to rename workspace!!",
"rename_team_success": "Workspace renamed successfully!",
"rename_user_failure": "Failed to rename user!!",
"rename_user_success": "User renamed successfully!!",
"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!!",
"selected": "{count} selected",
"self_host_docs": "Self Host Documentation",
"send_magic_link": "Send magic link",
"setup_failure": "Setup has failed!!",
Expand All @@ -164,7 +189,11 @@
"sign_in_options": "All sign in option",
"sign_out": "Sign out",
"team_name_too_short": "Workspace name should be atleast 6 characters long!!",
"user_not_found": "User not found in the infra!!"
"team_name_long": "Workspace name should be atleast 6 characters long!!",
"user_already_invited": "Failed to send invite. User is already invited!!",
"user_not_found": "User not found in the infra!!",
"users_to_admin_success": "Selected users are elevated to admin status!!",
"users_to_admin_failure": "Failed to elevate selected users to admin status!!"
},
"teams": {
"add_member": "Add Member",
Expand Down Expand Up @@ -201,7 +230,7 @@
"name": "Workspace Name",
"no_members": "No members in this workspace. Add members to this workspace to collaborate",
"no_pending_invites": "No pending invites",
"no_teams": "No workspaces found",
"no_teams": "No workspaces found..",
"pending_invites": "Pending invites",
"roles": "Roles",
"roles_description": "Roles are used to control access to the shared collections.",
Expand All @@ -226,16 +255,17 @@
"admin": "Admin",
"admin_email": "Admin Email",
"admin_id": "Admin ID",
"confirm_admin_to_user": "Do you want to remove admin status from this user?",
"confirm_user_deletion": "Confirm user deletion?",
"confirm_user_to_admin": "Do you want to make this user into an admin?",
"cancel": "Cancel",
"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",
Expand All @@ -245,14 +275,18 @@
"invitee_email": "Invitee Email",
"load_info_error": "Unable to load user info",
"load_list_error": "Unable to Load Users List",
"make_admin": "Make admin",
"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",
"pending_invites": "Pending Invites",
"remove_admin_privilege": "Remove Admin Privilege",
"remove_admin_status": "Remove Admin Status",
"rename": "Rename",
"revoke_invitation": "Revoke Invitation",
"searchbar_placeholder": "Search by name or email..",
"send_invite": "Send Invite",
"show_more": "Show more",
"uid": "UID",
Expand Down
4 changes: 2 additions & 2 deletions packages/hoppscotch-sh-admin/package.json
Expand Up @@ -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",
Expand Down Expand Up @@ -78,4 +78,4 @@
"singleQuote": true,
"semi": true
}
}
}
4 changes: 4 additions & 0 deletions packages/hoppscotch-sh-admin/src/components.d.ts
Expand Up @@ -29,8 +29,11 @@ declare module '@vue/runtime-core' {
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']
Expand All @@ -48,6 +51,7 @@ declare module '@vue/runtime-core' {
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']
}

}
103 changes: 99 additions & 4 deletions packages/hoppscotch-sh-admin/src/components/users/Details.vue
Expand Up @@ -24,11 +24,40 @@
</div>

<template v-for="(info, key) in userInfo" :key="key">
<div v-if="info.condition">
<label class="text-secondaryDark" :for="key">{{ info.label }}</label>
<div v-if="key === 'displayName'" class="flex flex-col space-y-3">
<label class="text-accentContrast" for="teamname"
>{{ t('users.name') }}
</label>
<div
class="w-full p-3 mt-2 bg-divider border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
class="flex bg-divider rounded-md items-stretch flex-1 border border-divider"
:class="{
'!border-accent': isNameBeingEdited,
}"
>
<HoppSmartInput
v-model="updatedUserName"
styles="bg-transparent flex-1 rounded-md !rounded-r-none disabled:select-none border-r-0 disabled:cursor-default disabled:opacity-50"
:placeholder="t('users.name')"
:disabled="!isNameBeingEdited"
>
<template #button>
<HoppButtonPrimary
class="!rounded-l-none"
filled
:icon="isNameBeingEdited ? IconSave : IconEdit"
:label="
isNameBeingEdited ? t('users.rename') : t('users.edit')
"
@click="handleNameEdit"
/>
</template>
</HoppSmartInput>
</div>
</div>

<div v-else-if="info.condition">
<label class="text-secondaryDark" :for="key">{{ info.label }}</label>
<div class="w-full p-3 mt-2 bg-divider border-gray-600 rounded-md">
<span>{{ info.value }}</span>
</div>
</div>
Expand Down Expand Up @@ -70,10 +99,17 @@
</template>

<script setup lang="ts">
import { useMutation } from '@urql/vue';
import { format } from 'date-fns';
import { computed, onMounted, ref } from 'vue';
import { useI18n } from '~/composables/i18n';
import { useToast } from '~/composables/toast';
import { UserInfoQuery } from '~/helpers/backend/graphql';
import {
UpdateUserDisplayNameByAdminDocument,
UserInfoQuery,
} from '~/helpers/backend/graphql';
import IconEdit from '~icons/lucide/edit';
import IconSave from '~icons/lucide/save';
import IconTrash from '~icons/lucide/trash';
import IconUserCheck from '~icons/lucide/user-check';
import IconUserMinus from '~icons/lucide/user-minus';
Expand All @@ -89,6 +125,7 @@ const emit = defineEmits<{
(event: 'delete-user', userID: string): void;
(event: 'make-admin', userID: string): void;
(event: 'remove-admin', userID: string): void;
(event: 'update-user-name', newName: string): void;
}>();

// Get Proper Date Formats
Expand Down Expand Up @@ -120,4 +157,62 @@ const userInfo = {
value: getCreatedDateAndTime(createdOn),
},
};

// Contains the actual user name
const userName = computed({
get: () => props.user.displayName,
set: (value) => {
return value;
},
});

// Contains the stored user name from the actual name before being edited
const currentUserName = ref('');

// Set the current user name to the actual user name
onMounted(() => {
if (displayName) currentUserName.value = displayName;
});

// Contains the user name that is being edited
const updatedUserName = computed({
get: () => currentUserName.value,
set: (value) => {
currentUserName.value = value;
},
});

// Rename the user
const isNameBeingEdited = ref(false);
const userRename = useMutation(UpdateUserDisplayNameByAdminDocument);

const handleNameEdit = () => {
if (isNameBeingEdited.value) {
// If the name is not changed, then return control
if (userName.value !== updatedUserName.value) {
renameUserName();
} else isNameBeingEdited.value = false;
} else {
isNameBeingEdited.value = true;
}
};

const renameUserName = async () => {
if (updatedUserName.value?.trim() === '') {
toast.error(t('users.empty_name'));
return;
}

const variables = { userUID: uid, name: updatedUserName.value as string };
const result = await userRename.executeMutation(variables);

if (result.error) {
toast.error(t('state.rename_user_failure'));
} else {
isNameBeingEdited.value = false;
toast.success(t('state.rename_user_success'));
emit('update-user-name', updatedUserName.value as string);
userName.value = updatedUserName.value;
}
};
</script>
Expand Up @@ -10,6 +10,7 @@
v-model="email"
:label="t('users.email_address')"
input-styles="floating-input"
@submit="sendInvite"
/>
</template>
<template #footer>
Expand All @@ -18,7 +19,12 @@
:label="t('users.send_invite')"
@click="sendInvite"
/>
<HoppButtonSecondary label="Cancel" outline filled @click="hideModal" />
<HoppButtonSecondary
:label="t('users.cancel')"
outline
filled
@click="hideModal"
/>
</span>
</template>
</HoppSmartModal>
Expand Down