grey out main admin and the user himself in avoidance of deleting the account by accident

This commit is contained in:
Yinyin Liu 2026-06-02 10:06:04 +02:00
parent 3a5c203664
commit 2cc8eebf37
6 changed files with 42 additions and 15 deletions

View File

@ -375,7 +375,8 @@ public static class SessionMethods
var emailOwner = Db.GetUserByEmail(editedUser.Email);
return sessionUser.UserType != 0
&& originalUser.Id != 0 // never edit the root user
&& originalUser.Id != 0 // belt: legacy root-id sentinel
&& originalUser.ParentId > 0 // never edit the main/root admin (parentless top user; ParentId<=0, Id NOT necessarily 0)
&& (sessionUser.UserType == 2 || sessionUser.HasAccessTo(originalUser)) // admins may edit any user
&& (emailOwner is null || emailOwner.Id == editedUser.Id) // email not taken by another user
&& editedUser
@ -402,7 +403,8 @@ public static class SessionMethods
return sessionUser is not null
&& userToDelete is not null
&& sessionUser.UserType !=0
&& userToDelete.Id != 0 // never delete the root user
&& userToDelete.Id != 0 // belt: legacy root-id sentinel
&& userToDelete.ParentId > 0 // never delete the main/root admin (the parentless top user; ParentId<=0, Id NOT necessarily 0)
&& userToDelete.Id != sessionUser.Id // never self-delete (avoid lockout)
&& (sessionUser.UserType == 2 || sessionUser.HasAccessTo(userToDelete)) // admins may delete any user
&& Db.Delete(userToDelete);

View File

@ -16,6 +16,7 @@ import {
Tab,
Tabs,
TextField,
Tooltip,
Typography,
useTheme
} from '@mui/material';
@ -24,6 +25,7 @@ import Button from '@mui/material/Button';
import axiosConfig from 'src/Resources/axiosConfig';
import { InnovEnergyUser } from 'src/interfaces/UserTypes';
import { TokenContext } from 'src/contexts/tokenContext';
import { UserContext } from 'src/contexts/userContext';
import { TabsContainerWrapper } from 'src/layouts/TabsContainerWrapper';
import { FormattedMessage, useIntl } from 'react-intl';
import UserAccess from '../ManageAccess/UserAccess';
@ -43,6 +45,8 @@ function User(props: singleUserProps) {
const [formValues, setFormValues] = useState(props.current_user);
const tokencontext = useContext(TokenContext);
const { removeToken } = tokencontext;
const userContext = useContext(UserContext);
const loggedInUser = userContext?.currentUser;
const tabs = [
{ value: 'user', label: intl.formatMessage({ id: 'user' }) },
{ value: 'manage', label: intl.formatMessage({ id: 'accessManagement' }) }
@ -161,6 +165,17 @@ function User(props: singleUserProps) {
const isMobile = window.innerWidth <= 1490;
// Mirror the backend delete guards: the main/root admin (the parentless top
// user — parentId 0; its id is NOT necessarily 0) and your own account can
// never be deleted, so disable the button and explain why.
const isMainAdmin = formValues.parentId <= 0 || formValues.id === 0;
const deleteDisabledReason = isMainAdmin
? intl.formatMessage({ id: 'cannotDeleteMainAdmin' })
: loggedInUser?.id === formValues.id
? intl.formatMessage({ id: 'cannotDeleteSelf' })
: '';
const cannotDelete = deleteDisabledReason !== '';
return (
<>
{openModalDeleteUser && (
@ -350,18 +365,20 @@ function User(props: singleUserProps) {
defaultMessage="Apply Changes"
/>
</Button>
<Tooltip title={deleteDisabledReason}>
<span style={{ marginLeft: '10px' }}>
<Button
variant="contained"
onClick={handleDelete}
sx={{
marginLeft: '10px'
}}
disabled={cannotDelete}
>
<FormattedMessage
id="delete_user"
defaultMessage="Delete User"
/>
</Button>
</span>
</Tooltip>
{loading && (
<CircularProgress

View File

@ -502,6 +502,8 @@
"connectingToDevice": "Verbindung zum Gerät wird hergestellt...",
"fetchingData": "Daten werden abgerufen...",
"confirmDeleteUser": "Möchten Sie diesen Benutzer löschen?",
"cannotDeleteSelf": "Sie können Ihr eigenes Konto nicht löschen",
"cannotDeleteMainAdmin": "Das Hauptadministrator-Konto kann nicht gelöscht werden",
"accessManagement": "Zugriffsverwaltung",
"power": "Leistung",
"voltage": "Spannung",

View File

@ -250,6 +250,8 @@
"connectingToDevice": "Connecting to the device...",
"fetchingData": "Fetching data...",
"confirmDeleteUser": "Do you want to delete this user?",
"cannotDeleteSelf": "You cannot delete your own account",
"cannotDeleteMainAdmin": "The main admin account cannot be deleted",
"accessManagement": "Access Management",
"power": "Power",
"voltage": "Voltage",

View File

@ -502,6 +502,8 @@
"connectingToDevice": "Connexion à l'appareil en cours...",
"fetchingData": "Récupération des données...",
"confirmDeleteUser": "Voulez-vous supprimer cet utilisateur ?",
"cannotDeleteSelf": "Vous ne pouvez pas supprimer votre propre compte",
"cannotDeleteMainAdmin": "Le compte de l'administrateur principal ne peut pas être supprimé",
"accessManagement": "Gestion des accès",
"power": "Puissance",
"voltage": "Tension",

View File

@ -502,6 +502,8 @@
"connectingToDevice": "Connessione al dispositivo in corso...",
"fetchingData": "Recupero dati in corso...",
"confirmDeleteUser": "Vuoi eliminare questo utente?",
"cannotDeleteSelf": "Non puoi eliminare il tuo account",
"cannotDeleteMainAdmin": "L'account dell'amministratore principale non può essere eliminato",
"accessManagement": "Gestione accessi",
"power": "Potenza",
"voltage": "Tensione",