From 9fd950342c8691916ce1e69b3fa30476aa807fb0 Mon Sep 17 00:00:00 2001 From: rique223 Date: Tue, 19 Mar 2024 17:45:54 -0300 Subject: [PATCH 1/8] feat: :sparkles: Add Deactivated users tab to users page tab layout Implemented a new tab in the users page called 'deactivated' that will list all users who have logged in for the first time but are deactivated for any reason, also added a useMemo to the table action menu for optimization and added logic to only show the Status change and Delete options in the menus of the table and the contextual bar when inside the deactivated and pending tabs. --- .../admin/users/AdminUserInfoActions.tsx | 22 ++++--- .../admin/users/AdminUserInfoWithData.tsx | 6 +- .../views/admin/users/AdminUsersPage.tsx | 2 +- .../admin/users/UsersTable/UsersTableRow.tsx | 61 +++++++++++-------- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx b/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx index c1052889f16f..7b1ef363b6cb 100644 --- a/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx @@ -1,4 +1,4 @@ -import type { IUser } from '@rocket.chat/core-typings'; +import type { IUser, IAdminUserTabs } from '@rocket.chat/core-typings'; import { ButtonGroup, Menu, Option } from '@rocket.chat/fuselage'; import { useRoute, usePermission, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; @@ -18,6 +18,7 @@ type AdminUserInfoActionsProps = { isFederatedUser: IUser['federated']; isActive: boolean; isAdmin: boolean; + tab: IAdminUserTabs; onChange: () => void; onReload: () => void; }; @@ -29,6 +30,7 @@ const AdminUserInfoActions = ({ isFederatedUser, isActive, isAdmin, + tab, onChange, onReload, }: AdminUserInfoActionsProps): ReactElement => { @@ -62,6 +64,7 @@ const AdminUserInfoActions = ({ [userId, userRoute], ); + const isNotPendingDeactivatedNorFederated = tab !== 'pending' && tab !== 'deactivated' && !isFederatedUser; const options = useMemo( () => ({ ...(canDirectMessage && { @@ -81,24 +84,25 @@ const AdminUserInfoActions = ({ disabled: isFederatedUser, }, }), - ...(changeAdminStatusAction && !isFederatedUser && { makeAdmin: changeAdminStatusAction }), - ...(resetE2EKeyAction && !isFederatedUser && { resetE2EKey: resetE2EKeyAction }), - ...(resetTOTPAction && !isFederatedUser && { resetTOTP: resetTOTPAction }), - ...(deleteUserAction && { delete: deleteUserAction }), + ...(isNotPendingDeactivatedNorFederated && changeAdminStatusAction && { makeAdmin: changeAdminStatusAction }), + ...(isNotPendingDeactivatedNorFederated && resetE2EKeyAction && { resetE2EKey: resetE2EKeyAction }), + ...(isNotPendingDeactivatedNorFederated && resetTOTPAction && { resetTOTP: resetTOTPAction }), ...(changeUserStatusAction && !isFederatedUser && { changeActiveStatus: changeUserStatusAction }), + ...(deleteUserAction && { delete: deleteUserAction }), }), [ - t, canDirectMessage, - directMessageClick, canEditOtherUserInfo, - editUserClick, changeAdminStatusAction, changeUserStatusAction, deleteUserAction, + directMessageClick, + editUserClick, + isFederatedUser, + isNotPendingDeactivatedNorFederated, resetE2EKeyAction, resetTOTPAction, - isFederatedUser, + t, ], ); diff --git a/apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx b/apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx index ee7bb4458311..3b91ef5275ee 100644 --- a/apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx @@ -1,4 +1,4 @@ -import type { IUser } from '@rocket.chat/core-typings'; +import type { IAdminUserTabs, IUser } from '@rocket.chat/core-typings'; import { Callout } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useSetting, useRolesDescription, useTranslation, useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; @@ -18,9 +18,10 @@ import AdminUserInfoActions from './AdminUserInfoActions'; type AdminUserInfoWithDataProps = { uid: IUser['_id']; onReload: () => void; + tab: IAdminUserTabs; }; -const AdminUserInfoWithData = ({ uid, onReload }: AdminUserInfoWithDataProps): ReactElement => { +const AdminUserInfoWithData = ({ uid, onReload, tab }: AdminUserInfoWithDataProps): ReactElement => { const t = useTranslation(); const getRoles = useRolesDescription(); const approveManuallyUsers = useSetting('Accounts_ManuallyApproveNewUsers'); @@ -123,6 +124,7 @@ const AdminUserInfoWithData = ({ uid, onReload }: AdminUserInfoWithDataProps): R isFederatedUser={!!data.user.federated} onChange={onChange} onReload={onReload} + tab={tab} /> } /> diff --git a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx index b7243af14739..1d33b5de2ccd 100644 --- a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx +++ b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx @@ -177,7 +177,7 @@ const AdminUsersPage = (): ReactElement => { router.navigate('/admin/users')} /> - {context === 'info' && id && } + {context === 'info' && id && } {context === 'edit' && id && } {!isRoutePrevented && context === 'new' && } {!isRoutePrevented && context === 'invite' && } diff --git a/apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx b/apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx index 727edbc7a188..f2e4128acd7b 100644 --- a/apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx +++ b/apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx @@ -65,33 +65,44 @@ const UsersTableRow = ({ user, onClick, onReload, isMobile, isLaptop, tab, isSea const resendWelcomeEmail = useSendWelcomeEmailMutation(); const isNotPendingDeactivatedNorFederated = tab !== 'pending' && tab !== 'deactivated' && !isFederatedUser; - const menuOptions = { - ...(isNotPendingDeactivatedNorFederated && - changeAdminStatusAction && { - makeAdmin: { - label: { label: changeAdminStatusAction.label, icon: changeAdminStatusAction.icon }, - action: changeAdminStatusAction.action, - }, + const menuOptions = useMemo( + () => ({ + ...(isNotPendingDeactivatedNorFederated && + changeAdminStatusAction && { + makeAdmin: { + label: { label: changeAdminStatusAction.label, icon: changeAdminStatusAction.icon }, + action: changeAdminStatusAction.action, + }, + }), + ...(isNotPendingDeactivatedNorFederated && + resetE2EKeyAction && { + resetE2EKey: { label: { label: resetE2EKeyAction.label, icon: resetE2EKeyAction.icon }, action: resetE2EKeyAction.action }, + }), + ...(isNotPendingDeactivatedNorFederated && + resetTOTPAction && { + resetTOTP: { label: { label: resetTOTPAction.label, icon: resetTOTPAction.icon }, action: resetTOTPAction.action }, + }), + ...(changeUserStatusAction && + !isFederatedUser && { + changeActiveStatus: { + label: { label: changeUserStatusAction.label, icon: changeUserStatusAction.icon }, + action: changeUserStatusAction.action, + }, + }), + ...(deleteUserAction && { + delete: { label: { label: deleteUserAction.label, icon: deleteUserAction.icon }, action: deleteUserAction.action }, }), - ...(isNotPendingDeactivatedNorFederated && - resetE2EKeyAction && { - resetE2EKey: { label: { label: resetE2EKeyAction.label, icon: resetE2EKeyAction.icon }, action: resetE2EKeyAction.action }, - }), - ...(isNotPendingDeactivatedNorFederated && - resetTOTPAction && { - resetTOTP: { label: { label: resetTOTPAction.label, icon: resetTOTPAction.icon }, action: resetTOTPAction.action }, - }), - ...(changeUserStatusAction && - !isFederatedUser && { - changeActiveStatus: { - label: { label: changeUserStatusAction.label, icon: changeUserStatusAction.icon }, - action: changeUserStatusAction.action, - }, - }), - ...(deleteUserAction && { - delete: { label: { label: deleteUserAction.label, icon: deleteUserAction.icon }, action: deleteUserAction.action }, }), - }; + [ + changeAdminStatusAction, + changeUserStatusAction, + deleteUserAction, + isFederatedUser, + isNotPendingDeactivatedNorFederated, + resetE2EKeyAction, + resetTOTPAction, + ], + ); const handleResendWelcomeEmail = () => resendWelcomeEmail.mutateAsync({ email: emails?.[0].address }); From 6ebd9047747d0e38565ef1781b0df515c474a2cc Mon Sep 17 00:00:00 2001 From: rique223 Date: Tue, 19 Mar 2024 18:02:04 -0300 Subject: [PATCH 2/8] refactor: :recycle: Improve variant verification for users page kebab menu --- .../client/views/admin/users/AdminUserInfoActions.tsx | 4 +++- .../views/admin/users/UsersTable/UsersTableRow.tsx | 10 +++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx b/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx index 7b1ef363b6cb..31238eb1c569 100644 --- a/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx @@ -121,7 +121,9 @@ const AdminUserInfoActions = ({ secondary flexShrink={0} key='menu' - renderItem={({ label: { label, icon }, ...props }): ReactElement =>