mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
feat(ui): prevent self-modification in People management and highlight current user (#5441)
# Description of Changes This PR improves the People management UI by preventing users from modifying or deleting their own account and by visually highlighting the currently logged-in user. <img width="675" height="196" alt="image" src="https://github.com/user-attachments/assets/c45fb0b6-c766-412c-a53b-b72aed2925d2" /> ### What was changed - Integrated session-based authentication context to identify the currently logged-in user. - Added a helper to detect the current user in the user list. - Highlighted the current user's row with a subtle background color. - Disabled self-actions: - Editing own role - Enabling/disabling own account - Deleting own account - Kept password change available for the current user. ### Why the change was made - Prevents accidental self-lockout or privilege removal. - Aligns UI behavior with common security best practices. - Improves clarity by visually distinguishing the active user account. --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details.
This commit is contained in:
@@ -31,11 +31,13 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import UpdateSeatsButton from '@app/components/shared/UpdateSeatsButton';
|
import UpdateSeatsButton from '@app/components/shared/UpdateSeatsButton';
|
||||||
import { useLicense } from '@app/contexts/LicenseContext';
|
import { useLicense } from '@app/contexts/LicenseContext';
|
||||||
import ChangeUserPasswordModal from '@app/components/shared/ChangeUserPasswordModal';
|
import ChangeUserPasswordModal from '@app/components/shared/ChangeUserPasswordModal';
|
||||||
|
import { useAuth } from '@app/auth/UseSession';
|
||||||
|
|
||||||
export default function PeopleSection() {
|
export default function PeopleSection() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { config } = useAppConfig();
|
const { config } = useAppConfig();
|
||||||
const { loginEnabled } = useLoginRequired();
|
const { loginEnabled } = useLoginRequired();
|
||||||
|
const { user: currentUser } = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { licenseInfo: globalLicenseInfo } = useLicense();
|
const { licenseInfo: globalLicenseInfo } = useLicense();
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
@@ -77,6 +79,7 @@ export default function PeopleSection() {
|
|||||||
? t('workspace.people.license.noSlotsAvailable', 'No user slots available')
|
? t('workspace.people.license.noSlotsAvailable', 'No user slots available')
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const isCurrentUser = (user: User) => currentUser?.username === user.username;
|
||||||
|
|
||||||
// Form state for edit user modal
|
// Form state for edit user modal
|
||||||
const [editForm, setEditForm] = useState({
|
const [editForm, setEditForm] = useState({
|
||||||
@@ -463,7 +466,10 @@ export default function PeopleSection() {
|
|||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
) : (
|
) : (
|
||||||
filteredUsers.map((user) => (
|
filteredUsers.map((user) => (
|
||||||
<Table.Tr key={user.id}>
|
<Table.Tr
|
||||||
|
key={user.id}
|
||||||
|
style={isCurrentUser(user) ? { backgroundColor: 'rgba(34, 139, 230, 0.08)' } : undefined}
|
||||||
|
>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Group gap="xs" wrap="nowrap">
|
<Group gap="xs" wrap="nowrap">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@@ -577,6 +583,7 @@ export default function PeopleSection() {
|
|||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown style={{ zIndex: Z_INDEX_OVER_CONFIG_MODAL }}>
|
<Menu.Dropdown style={{ zIndex: Z_INDEX_OVER_CONFIG_MODAL }}>
|
||||||
|
{!isCurrentUser(user) && (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leftSection={<LocalIcon icon="edit" width="1rem" height="1rem" />}
|
leftSection={<LocalIcon icon="edit" width="1rem" height="1rem" />}
|
||||||
onClick={() => openEditModal(user)}
|
onClick={() => openEditModal(user)}
|
||||||
@@ -584,6 +591,7 @@ export default function PeopleSection() {
|
|||||||
>
|
>
|
||||||
{t('workspace.people.editRole')}
|
{t('workspace.people.editRole')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
)}
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leftSection={<LocalIcon icon="lock" width="1rem" height="1rem" />}
|
leftSection={<LocalIcon icon="lock" width="1rem" height="1rem" />}
|
||||||
onClick={() => openChangePasswordModal(user)}
|
onClick={() => openChangePasswordModal(user)}
|
||||||
@@ -591,6 +599,7 @@ export default function PeopleSection() {
|
|||||||
>
|
>
|
||||||
{t('workspace.people.changePassword.action', 'Change password')}
|
{t('workspace.people.changePassword.action', 'Change password')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
{!isCurrentUser(user) && (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leftSection={user.enabled ? <LocalIcon icon="person-off" width="1rem" height="1rem" /> : <LocalIcon icon="person-check" width="1rem" height="1rem" />}
|
leftSection={user.enabled ? <LocalIcon icon="person-off" width="1rem" height="1rem" /> : <LocalIcon icon="person-check" width="1rem" height="1rem" />}
|
||||||
onClick={() => handleToggleEnabled(user)}
|
onClick={() => handleToggleEnabled(user)}
|
||||||
@@ -598,10 +607,15 @@ export default function PeopleSection() {
|
|||||||
>
|
>
|
||||||
{user.enabled ? t('workspace.people.disable') : t('workspace.people.enable')}
|
{user.enabled ? t('workspace.people.disable') : t('workspace.people.enable')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
{!isCurrentUser(user) && (
|
||||||
|
<>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item color="red" leftSection={<LocalIcon icon="delete" width="1rem" height="1rem" />} onClick={() => handleDeleteUser(user)} disabled={!loginEnabled}>
|
<Menu.Item color="red" leftSection={<LocalIcon icon="delete" width="1rem" height="1rem" />} onClick={() => handleDeleteUser(user)} disabled={!loginEnabled}>
|
||||||
{t('workspace.people.deleteUser')}
|
{t('workspace.people.deleteUser')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user